Redirect 301 con CloudFront y Lambda@EDGE
Tags: devops, programming, tutorial, productivity
Published: 2023-03-21 13:08:24

Hace poco tuve un requerimiento que consistía en redirigir una URL registrada en Route53 hacia una Progressive Web Application (PWA) deployada en un Bucket de S3 y distribuida a través de Cloudfront con subdominio propio.

Para mi sorpresa, AWS no puede realizar esa petición utilizando los servicios antes mencionados de una manera simple. En este artículo les voy a contar cómo hacerlo paso por paso.

## ¿Qué es un Código de estado de respuesta HTTP 301?
Existen diversos códigos de estado como respuesta a una petición HTTP, entre ellos el código 301, el cual indica un redireccionamiento permanente de una URL a otra, enviando a todos los usuarios a la nueva URL destino. Comúnmente se utiliza cuando cambiamos de URL una web ya existente.

Para más información, leer:

[Códigos de estado de respuesta HTTP](https://developer.mozilla.org/es/docs/Web/HTTP/Status)

## Manos a la obra
Para realizar la redirección solicitada vamos a crear una función Lambda@EDGE que evalúe el host de un request y, si empata con la URL que queremos redirigir, realice un redirect 301 a la URL de nuestra PWA. Esa función vamos a asociarla a la distribución de CloudFront donde se encuentra la PWA.

Resumiendo, lo que hay que hacer es:

1. Ir a [CloudFront](https://aws.amazon.com/es/cloudfront/) y agregar nuestra URL, la que queremos redirigir, como un Alternative domain names. Para ello, nos dirigimos a nuestra distribución de CloudFront, en la pestaña general editamos los Settings y agregamos un **Alternative domain name (CNAME)** colocando la URL a la que vamos a aplicarle el Redirect 301.

2. Ahora tenemos que vincular nuestra URL a redirigir con la distribución de CloudFront. Para hacerlo, dirigirse a Route53, crear un record tipo A y colocar la misma URL que agregamos en el paso anterior. Vamos a filtrar la distribución de CloudFront buscándola por Alias y veremos que cuando seleccionemos CloudFront automáticamente nos va a aparecer la opción para elegir la distribución de nuestra PWA, gracias a que previamente agregamos ese dominio como Alternative domain name a nuestra distribución.

3. Por último, realizar un función lambda@EDGE y asociarla a nuestra distribución CloudFront para que cuando accedamos mediante la urlARedirigir realice una respuesta 301 y nos redirija a la URL original de la PWA. Para esto, vamos a ir a Lambda -> Create Function y elegimos Author from Scratch. Vamos a utilizar NodeJs y una arquitectura x86 para crear nuestra función.


Una vez creada la función nos va a salir un código de muestra, el cuál hay que editar y agregar el siguiente código:

```

exports.handler = async (event) => {
  const request = event.Records[0].cf.request;
  if (request.headers.host[0].value === 'urlARedirigir') {
    return {
      status: '301',
      statusDescription: `Redirecting to other domain`,
      headers: {
        location: [{
          key: 'Location',
          value: `https://urlPWA${request.uri}`
        }]
      }
    };
  }
  return request;
};
```

> Un detalle importante respecto a la función es que urlARedirigir es solo el HOST de nuestra URL, por ende su valor NO debe contener el protocolo.
> Ejemplo:
> URL = https://exampleUrl.com
> Host = exampleUrl.com

Luego de ingresar el código realizamos un deploy (presionando el botón ubicado arriba del cuadro de código) y debemos realizar una publicación de nuestra función Lambda desde el desplegable action -> publish new version.


Antes de continuar triggereando nuestra función con nuestra distribución de CloudFront, hay que ir a la solapa de Configuration y seleccionar Permission en la columna de la izquierda. Allí veremos que existe un ROLE creado. Clickeamos sobre el nombre del rol y nos va a dirigir al servicio de IAM.


Dentro del servicio de la configuración del ROL en el servicio de IAM nos dirigimos a la solapa de Permissions y editamos la Policy creada agregándole varios permisos, dejándola así:

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:us-east-1:<accountID>:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "lambda:GetFunction",
                "lambda:EnableReplication*",
                "iam:CreateServiceLinkedRole",
                "cloudfront:UpdateDistribution",
                "cloudfront:CreateDistribution"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:<accountID>:log-group:/aws/lambda/redirect301:*",
                "arn:aws:cloudfront::<accountID>:distribution/*",
                "arn:aws:lambda:*:<accountID>:function:*",
                "arn:aws:iam::*:role/*"
            ]
        }
    ]
}
```


Luego, nos dirigimos a la solapa de Trust relationships, clickeamos el botón Edit trust relationship y editamos la policy para que quede de la siguiente manera:

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "lambda.amazonaws.com",
          "edgelambda.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```


Una vez realizado este cambio volvemos al servicio de Lambda y vamos a nuestra función. Tocamos el botón Add trigger y seleccionamos el servicio de CloudFront. A continuación, tocamos el botón de Deploy to Lambda@Edge. Esto nos va a levantar un popup donde seleccionaremos la distribución de CloudFront donde se encuentra nuestra PWA, seleccionaremos Viewer request como evento de nuestra distribución y, por último, damos el check confirmando el deploy y presionamos “Deploy”.

Una vez deployado el trigger podemos observar que en nuestra pantalla de la función aparece el servicio de CLoudFront. Por último, si vamos a la sección de Behavior de nuestra distribución de CloudFront veremos que en la parte de Functions Associations se encuentra en el Viewer Request nuestro Lambda@Edge recién creado.


¡Y eso es todo!

Gracias por haber leído, espero que les sea útil. Pueden dejar sus dudas o comentarios abajo.