¿Cómo asignar un subdominio en CloudFront con el mismo nombre en S3?

¿Cómo asignar un subdominio en CloudFront con el mismo nombre en S3?

He estado buscando una manera de hacer lo siguiente, si alguien pudiera iluminarme se lo agradecería mucho.

por ejemplo, ¿serían posibles las siguientes asignaciones en una única instancia de CloudFront?

feature-a.domain.com => dev-bucket/feature-a
feature-b.domain.com => dev-bucket/feature-b
staging.domain.com   => dev-bucket/staging

Etcétera..

El caso de uso es que quiero poder implementar tantos entornos para cada rama de git que se asigne a un depósito en S3 que exista. ¿Sería todo esto posible?

Respuesta1

Sí, es posible, pero necesitará utilizar la mejora Lambda@Edge en CloudFront para poder manipular los parámetros de la solicitud antes de enviar la solicitud al depósito.

Describí una posible solución enesta publicación oficial del foro. Esa misma solución se incluye a continuación.

Lambda@Edge permite el acceso programático a las solicitudes o respuestas HTTP mientras CloudFront las procesa, proporcionando esencialmente enlaces de activación. La transacción HTTP se presenta como un objeto javascript que puede observar, modificar y luego devolver el control a CloudFront.

Para esta aplicación, debe utilizar el punto final de alojamiento del sitio web del depósito como su nombre de dominio de origen en la configuración de CloudFront (es decir, no seleccione el depósito en el menú desplegable; escríbalo usando el nombre de host "s3-website" apropiado). ) y necesita incluir el Hostencabezado en la lista blanca para reenviarlo al origen, aunque en realidad no lo reenviaremos (lo leeremos y luego lo manipularemos, junto con la ruta) y aunque, normalmente, lo reenviaremos a un origen S3 no funcionaría según lo previsto... pero debemos decirle a CloudFront que lo incluya en la lista blanca para que pueda leerse y manipularse.

Configure la siguiente función Lambda como activador de solicitud de origen. Este disparador se activa después de que se verifica el caché de CloudFront y se produce una pérdida de caché, y antes de que la solicitud se envíe al servidor de origen (S3).

'use strict';

// https://serverfault.com/a/930191/153161
// if the end of incoming Host header matches this string, 
// strip this part and prepend the remaining characters onto the request path,
// along with a new leading slash (otherwise, the request will be handled
// with an unmodified path, at the root of the bucket)

// set this to what we should remove from the incoming hostname, including the leading dot.

const remove_suffix = '.example.com';

// provide the correct origin hostname here so that we send the correct 
// Host header to the S3 website endpoint
// this is the same value as "origin domain name" in the cloudfront distribution configuration

const origin_hostname = 'example-bucket.s3-website-us-east-1.amazonaws.com';

exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;
  const host_header = headers.host[0].value;

  if(host_header.endsWith(remove_suffix))
  {
    // prepend '/' + the subdomain onto the existing request path ("uri")
    request.uri = '/' + host_header.substring(0,host_header.length - remove_suffix.length) + request.uri;
  }

  // fix the host header so that S3 understands the request
  // we have to do this even if the above if() didn't match
  headers.host[0].value = origin_hostname;

  // return control to CloudFront with the modified request
  return callback(null,request);
};

Recuerde también configurar suerror de almacenamiento en caché TTL mínimo a 0para evitar tener respuestas de error de caché de CloudFront. Esta es una configuración separada del TTL mínimo/predeterminado/máximo en la configuración de Comportamiento de caché. El valor predeterminado es 5 minutos, lo cual tiene sentido, pero complica la resolución de problemas si no anticipa este comportamiento.


Tenga en cuenta que las funciones Lambda@Edge ahora pueden usar la versión 6.10 ov8.10Entorno de ejecución de Node.js. El ejemplo anterior se escribió originalmente para la versión 6.10, pero es compatible con cualquiera de los tiempos de ejecución porque en la versión 8.10 el controlador tiene más opciones: puede usar async/await, puede devolver una promesa directamente o puede escribirse como se muestra arriba. para utilizar la interfaz de devolución de llamada.

información relacionada