cloudformation + lambda + lambda

Итак, редиректы без сервера, как это можно сделать с помощью сервисов AWS? Для начала, давайте определимся, зачем это вообще может понадобиться. У меня возникла довольно простая с точки зрения бизнеса задача - настроить редиректы на региональные домены. К примеру: mysite.customerdomain.com -> mysite.location.customerdomain.com. Делается это элементарно, с помощью rewrite-правил или того-же mod_alias для Apache HTTPD, если сайты работают на одном веб-сервере. В нашем же случае это несколько статических веб-приложений в S3 + CDN и бекэнд в виде микро-сервисов. Поэтому добавлять еще один веб-сервер и усложнять автоматизацию при работе с CloudFormation и Route53 не очень-то и хотелось.

Варианты

Для начала посмотрим на ситуацию в целом, для решения поставленной задачи есть несколько подходов:

  • Стандартный с помощью DNS, Web-server’a и редиректов
  • Использовать AWS сервисы и совсем немного JavaScript

Option 1: Old-style

Вариант довольно стандартный, работает на любой инфраструктуре и практически с любым DNS провайдером.

Рецепт:

  1. Поднимаем VM или контейнер и конфигурируем веб-сервер
  2. Настраиваем правила для редиректов: Nginx, Apache HTTPD попроще, Apache HTTPD посложнее
  3. Делаем CNAME для основных доменов на наш вновь-созданный application-router или redirect-service, кому как больше нравится
  4. Создаем новые DNS записи для текущих приложений
  5. Проверяем :)

На выходе имеем полноценные редиректы, которые возможно конфигурировать довольно сложным образом, при необходимости, и при этом у нас не возникает vendor-lock’a.

Давайте посмотрим как подобное можно сделать только средствами AWS.

Option 2: Serverless approach

Подобное? Именно, потому, что этот вариант будет работать только в браузерах с включенной поддержкой JavaScript. Нас это ограничение полностью устраивало, так как весь бэк-энд будет работать напрямую с новыми ссылками, а редиректы нужны были для старых ссылок пользователей, поэтому вариант с выключенным JavaScript в принципе не рассматривался.

Начнем мы с краткого обзора решений, которые предлагает AWS, а также причины, по которым они нам не подходят:

  • Is there a way to redirect a domain to another domain using Amazon Route 53?

    В чем проблема?

    Note: The sites must be HTTP, because the redirect cannot connect to S3 over HTTPS.

  • Configure a Bucket for Website Hosting

    Описание возможностей редиректов для S3-bucket, широкие возможности, но из-за отсутствия поддержки HTTPS ситуацию не спасает.

  • Amazon S3 - HTTPS/SSL - Is it possible? [closed]

    Интересный вопрос, на StackOverflow, в котором была копия официально ответа из отдела поддержки AWS, а также ссылка на официальное решение проблемы от AWS.

  • Amazon CloudFront Custom SSL

    Официальный ответ Amazon, по решению проблемы SSL для Static-Site hosting + S3 - CloudFront CDN и custom SNI certificates.

Собственно, исходя из всего вышеперечисленного для редиректа пользователей у нас остается JavaScript.

Идея заключается в том, чтобы в корзину положить единственный index.html, вот такого содержания:

<html>
  <body>
    <script>
      location.host = "mysite.location.customerdomain.com";
    </script>
  </body>
</html>

Работать это будет следующим образом:

  1. Пользователь запрашивает URL: http://mysite.customerdomain.com
  2. CDN сразу делает редирект на: https://mysite.customerdomain.com
  3. Браузер загружает index.html и отправляет пользователя на https://mysite.location.customerdomain.com
    JavaScript, MDN, Location

Все казалось бы просто, но не тут то было.

Технические подробности

Первый нюанс, это то, что нам обязательно нужно поставить параметр Default Root Object равным index.html, чтобы по умолчанию нам возвращалась наша страничка, даже если пользователь просто обратиться к корневому пути: / (https://mysite.customerdomain.com/).

AWS Console -> CloudFront -> Distribution settings -> General -> Edit:

cloudformation

Далее, возникает вопрос, а что делать со ссылками, к примеру: https://mysite.customerdomain.com/password-reset ? Нам же нужно сохранять и путь, и параметры.

В дефолтной конфигурации, CDN Вам либо ответит:

  • 404 Not Found
  • 403 Not Authorized, в зависимости от конфигурации policy S3-bucket.

К счастью для нас, у CloudFront CDN есть возможность сделать персонализированные странички для ошибок(AWS Console -> CloudFront -> Distribution settings -> Error Pages) и что более важно выбрать каким HTTP-кодом отвечать браузеру.

Выглядит это так:

cloudformation

Идея в том, чтобы при ошибке, мы все равно попадали на index.html, c полным URL, который потом сделает нужный редирект.

Теперь, при запросах вида: http://mysite.customerdomain.com/password-reset будет происходить редирект на https://mysite.location.customerdomain.com/password-reset , что позволит нам сохранить совместимость со всеми старыми ссылками.

Немного о конфигурации S3-bucket

Есть 3 основные вещи, которые нужно сделать:

  1. Загрузить index.html c содержимым выше
  2. Включить Static Website Hosting cloudformation
  3. Настроить S3-Bucket Policy
{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "custom1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CustomCloudFrontUser"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::website-bucket-name/*"
        }
    ]
}

Итого

При использовании CDN и JavaScript для редиректов, мягко говоря возникает вопрос резонности и целесообразности, а также стоимости такого решения.

Так как это бизнес требование, то предлагаю начать с цен:

  United States Canada Europe Hong Kong, Philippines, S. Korea, Singapore & Taiwan Japan South America Australia India Reserved Capacity Pricing
HTTP requests $0.0075 $0.0075 $0.0090 $0.0090 $0.0090 $0.0160 $0.0090 $0.0090 Contact Us
HTTPS requests $0.0100 $0.0100 $0.0120 $0.0120 $0.0120 $0.0220 $0.0125 $0.0120 Contact Us

При самых грубых подсчетах: $0.0075 + $0.01 = $0.0175 за 10 000 запросов. При том, что минимум за EC2 Instance мы будем платить от ~$10-15 в месяц.

Но, несмотря на все это, у решения есть недостатки:

  • это не полноценный редирект и рассчитан только для работы в современных браузерах
  • CloudFront ведет себя довольно непредсказуемо при первоначальной настройке и загрузке страницы, уходило какое-то время(несколько часов), пока он нормально кешировал этот объект(возможно из-за редиректов)
  • Downtime, при изменение DNS, а с учетом DNS-кэша у пользователей могут возникать странные ошибки

В нашем случае этот вариант полностью нас устраивал и имел существенные преимущества в плане экономии времени разработки и внедрения, т.к. интеграция нового сервиса в CloudFormation, скрипты и Continuos Delviery процесс, а также их тестирование было бы мягко говоря длительным и трудоемким, а необходимость в поддержке этих редиректов - временная.

В целом используя возможности AWS-платформы и стандартный функционал JavaScript мы оригинально решили поставленную задачу.

Спасибо за внимание.