Pull to refresh

Amazon CloudFront + Custom Origins

Reading time10 min
Views14K
Уже около года как Amazon добавила поддержку Custom Origins для своего сервиса CloudFront и на мой взгляд это очень хорошо, т.к. я давно присматривался к разным CDN.

Честно говоря трудно найти сейчас CDN для небольшого проекта или для старта, когда трафик по расчетам не должен превышать 50 — 100 Гб в месяц. Они либо очень дорогие, либо работают только с теми сайтами, которые генерируют большой трафик и почти все работают по предоплате, т.е. Вы платите не за фактически использованный трафик, а за какой-то объем, который можете и не выработать.

Amazon CloudFront в этом отношении выгодно отличается от конкурентов. Плата тут взымается только за фактически использованный трафик и она довольно невелика, в зависимости от региона она в среднем составляет 0.15$ за Гб трафика. Но раньше приходилось использовать CloudFront в паре с сервисом S3, что увеличивало стоимость, теперь же можно использовать Ваш собственный сервер в качестве origin сервера.

Я хотел бы рассказать подробно о том как я подключался, оплачивал и добавлял поддержку CloudFront у себя в проекте.

Оплата


Сперва хочу рассказать о том как я оплачиваю сервис и с какими трудностями я столкнулся на этом этапе.

Итак, я сам из Украины, но думаю что для всех или многих стран СНГ эта информация будет актуальной. Единственной формой оплаты, которую предложили мне на Amazon является оплата при помощи кредитной карточки. Т.е. никаких электронных денег типа WebMoney не принимают. Посему пришлось идти в банк и открывать кредитку. Я выбрал Аваль, хотя скорее всего банк не имеет большого значения, зато значение имеет сама кредитка. Я открыл себе долларовую Visa Classic, причем когда открывал уточнил у банковского работника смогу ли я оплачивать при помощи этой карточки покупки в интернете на зарубежных сайтах. Открытие карточки заняло 10 рабочих дней.

Теперь о проблемах, с которыми я столкнулся:
1. Активация карточки — тут признаться я сам немного протупил. Я положил через кассу банка деньги на карточку, но оказывается что карточка активируется когда произведешь с ней какое-то действие через банкомат (при этом на ней уже должны лежать деньги), подойдет даже проверка баланса. В любом случае стоит уточнить у работника банка как именно активируется карточка в их банке.

2. CVV — Amazon, что меня очень удивило, не запрашивает CVV код карточки. При регистрации нужно ввести только номер карточки, дату, до которой она действует и имя владельца карточки. Как оказалась Amazon работает по какой-то схеме где не требуется этот CVV, зато Вам требуется, на моменты оплаты или навсегда, отключить защиту своей карточки по CVV коду. Это можно сделать в телефонном режиме через call-центр банка или написав заявление в том отделении, где Вы открывали карточку.

В принципе это все проблемы которые возникли у меня с оплатой.

Регистрация и ключи


Процесс регистрации можно начать со страницы CloudFront. Регистрация очень проста, на одном из шагов регистрации нужно будет ввести информацию о карточке и если она пройдет валидацию то будет зарегистрирован аккаунт. Вместе с аккаунтом CloudFront будет автоматически создан аккаунт для сервиса S3, даже если мы хотим использовать Custom Origins.

После регистрации нужно сгенерировать ключи, которые понадобятся для общения с API и для формирования защищенных URL на Ваши файлы. Для этого переходим в раздел Security Credentials Вашего аккаунта. Тут Вы найдете 3-и вкладки:
1. Access Keys — данные с этой вкладки понадобятся для формирования авторизационного заголовка при запросах к API;

2. X.509 certificates — ключи для запросов к API через SOAP;

3. Key Pairs — ключи для формирования защищенных URL.

Стандартные заголовки при общении с REST API



Во всех запросах к REST API должны присутствовать следующие заголовки:
1. x-amz-date — дата запроса. Дата должна быть в одном из форматов описанных в спецификации RFC 2616 раздел «Date/Time Formats»;

2. Content-Type — тип тела запроса, обычно «application/xml»;

3. Content-Length — длина тела запроса;

4. Authorization — заголовок авторизации, имеет следующую структуру: «AWS aws_secret_key_id:signature», где:
4.1 AWS — константная строка, после которой обязательно идет пробельный символ;
4.2 aws_secret_key_id — можно найти на странице Security Credentials Вашего аккаунта в во вкладке «Access Keys»;
4.3 signature — контрольная подпись, которая сгенерирована при помощи алгоритма хеширования sha1, на основе даты запроса, которую вы указали в заголовке x-amz-date и секретного ключа, который можно найти на странице где расположен aws_secret_key_id. Ниже приведен PHP код который генерирует signature:
  1. $signature = base64_encode(hash_hmac('sha1', $requestDate, $awsSecretKey, true));

Distribution



Для того, что бы появилась возможность раздавать файлы через Amazon CloudFront необходимо создать Distribution.
На одном аккаунте можно создать максимум 100 Distribution-ов, количество файлов в одном Distribution не ограничено.
Distribution бывают 2-х типов:
1. Download — для раздачи файлов через протоколы HTTP и HTTPS (HTTPS немного дороже);

2. Stream — для раздачи видео и аудио файлов через протокол RTMP. Хочу сразу разочаровать, Distribution вида Stream не работают с Custom Origins, только с S3 в качестве origin сервера.

Исходя из названия статьи и пункта 2 я буду рассматривать только Download Distribution. Сразу приведу пример XML запроса на создание нового Download Distribution:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <DistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2010-11-01/">
  3.    <CustomOrigin>
  4.       <DNSName>www.example.com</DNSName>
  5.       <HTTPPort>80</HTTPPort>
  6.       <OriginProtocolPolicy>http-only</OriginProtocolPolicy>
  7.    </CustomOrigin>
  8.    <CallerReference>your unique caller reference</CallerReference>
  9.    <CNAME>mysite.example.com</CNAME>
  10.    <Comment>My comments</Comment>
  11.    <Enabled>true</Enabled>
  12.    <TrustedSigners><Self/></TrustedSigners>
  13.    <Logging>
  14.       <Bucket>mylogs.s3.amazonaws.com</Bucket>
  15.       <Prefix>myprefix/</Prefix>
  16.    </Logging>
  17. </DistributionConfig>

URL для запроса: cloudfront.amazonaws.com/2010–11–01/distribution
Метод запроса: POST

Опишу подробнее что означает каждый из тегов:
1. CustomOrigin — это область в которой задаются параметры Вашего origin сервера:
1.1 DNSName — домен origin сервера;
1.2 HTTPPort — порт для доступа к origin серверу по протоколу HTTP;
1.3 OriginProtocolPolicy — Amazon может запрашивать файлы с Вашего origin сервера двумя способами: http-only — всегда по HTTP протоколу, match-viewer — по протоколу, который использовал конечный пользователь для запроса файла, но только HTTP или HTTPS.
2. CallerReference — уникальный идентификатор для запроса, он может быть как числовым так и алфавитным, главное что бы был уникальным;
3. CNAME — для каждого Distribution Amazon создает поддомен для домена cloudfront.net. На этот домен Вы можете повесить один или несколько CNAME-ов;
4. Comment — комментарий для Distribution;
5. Enabled — устанавливает активен Distribution или нет;
6. TrustedSigners — Distribution-ы делятся так же и по типу доступа к ним на публичные и приватные. Доступ к файлам в публичных Distribution-ах имеют все, а для доступа к приватным нужно формировать защищенный URL, в котором можно указать срок годности, доступы по IP и другое. Именно для создания приватного Distribution-а нужно указывать эту секцию;
7. Logging — секция для задания параметров логирования запросов:
7.1 Bucket — для сохранения логов Amazon использует сервис S3, так что если Вы хотите их использовать придется доплачивать еще и за S3. Этот параметр задает S3 Bucket, в котором будут хранится логи;
7.2 Prefix — префикс логов, я так понимаю что это что-то вроде каталога для логов.

Сразу после создания Distribution-а он находится в статусе InProgress, но начинать работать с ним можно только после того как он сменит статус на Active. Обычно это занимает 10–15 минут. Для проверки статуса Distribution-а можно воспользоватся запросом к API на получения информации о Distribution.

URL для запроса: cloudfront.amazonaws.com/2010–11–01/distribution/distribution_id
Метод запроса: GET

distribution_id — Amazon возвращает в ответ на успешный запрос о создании Distribution-а.

Особенности отдачи файлов


Вот мы и добрались до самого главного — отдача наших файлов через CDN. Тут есть несколько особенностей:
1. Amazon CloudFront не транслирует на origin сервер никаких параметров URL-а, которые были переданы при запросе файла с CDN.Т. е. если конечный пользователь запросил файл example_sub_domain.cloudfront.net/image_1.jpg?param=value, то при запросе этого файла с origin сервера Вы не получите «param=value», НО в логах будет полный URL;

2. Обновление файла в Distribution. Файл может быть запрошен в следующих случаях:
2.1 Если он отсутствует на сервере CloudFront;
2.2 Если файл проэкспайрился. Датой экспайра можно управлять при помощи заголовков: cache-control, expires и pragma. По умолчанию файл кешируется на 24 часа;
2.3 Если файл был удален из Distribution-а при помощи запроса Invalidation;
Следует обратить внимание на то, что при запросе файла конечным пользователем, Amazon не проверяет дату модификации файла как делают это другие CDN. Если Вы хотите что бы при изменении файла он был автоматически подхвачен сервером Amazon-а, то нужно в названии файла указывать его версию или дату модификации.

3. Защита файлов на стороне origin — если Вы используете в качестве origin сервера свой собственный (т.е. как раз тот случай, который я описываю в статье) то Amazon никак не обеспечивает защиту файлов на Вашем origin сервере от несанкционированного доступа, эта задача полностью лежит на владельце origin-а. Но при этом защита файлов должна быть осуществлена таким образом, что бы сам Amazon имел доступ к этим файлам по протоколу HTTP или HTTPS. При этом Amazon при запросе файла не шлет никаких данных, по которым его запросы можно было бы отличить от других. Исходя из этого есть только один вариант защиты member файлов на Вашем origin сервере — защита по IP. У себя member файлы я защищаю при помощи .htaccess следующего вида:

  1. Order Deny,Allow
  2. Deny from all


для того, что бы Amazon имел доступ к моим файлам я добавил в .htaccess следующее правило 
  1. # Amazon CloudFront
  2. Allow from 216.137.60.0/23


Маску 216.137.60.0/23 я взял вот тут.

Публичный URL


Допустим что файл доступен на Вашем origin сервере по адресу:

  1. origin.example.com/images/image_1.jpg


Тогда для того что бы отдать его через Amazon CloudFront вам нужно сформировать следующий URL:

  1. example_sub_domain.cloudfront.net/images/image_1.jpg


где example_sub_domain.cloudfront.net — это домен того Distribution-а, который соответствует origin-у origin.example.com.

Приватный URL


Приватные URL делятся на два вида:
1. Сanned — можно указать только срок годности URL;
2. Custom — можно указать период когда URl будет валиден, а так же один или несколько IP адресов, с которых можно будет воспользоваться URL-ом.

Мне нужны была только дата, до которой URL будет валиден, так что я приведу пример для генерации Сanned URL:

  1. function getSignedUrl($url)
  2. {
  3.         // Prepare expire date
  4.         $expireDate = time() + SECURE_URL_TIMEOUT;
  5.        
  6.         // Read Cloudfront Private Key Pair
  7.         $fp = fopen(CLOUD_FRONT_KEY_PAIR_PATH, "r");
  8.         $privateKey = fread($fp, 8192);
  9.         fclose($fp);
  10.  
  11.         // Create the private key
  12.         $privateKey = openssl_get_privatekey($privateKey);
  13.         if (!$privateKey) {
  14.                 return false;
  15.         }
  16.        
  17.         // Prepare json policy
  18.         $json = '{"Statement":[{"Resource":"'.$url.'","Condition":{"DateLessThan":{"AWS:EpochTime":'.$expireDate.'}}}]}';
  19.        
  20.         // Sign the policy with the private key
  21.         if(!openssl_sign($json, $signature, $privateKey, OPENSSL_ALGO_SHA1)) {
  22.                 return false;
  23.         }
  24.        
  25.         // Create url safe signed policy
  26.         $signature = str_replace(array('+','=','/'), array('-','_','~'), base64_encode($signature));
  27.  
  28.         //Construct the URL
  29.         return $url
  30.                 . '?Expires=' . $expireDate
  31.                 . '&Signature=' . $signature
  32.                 . '&Key-Pair-Id=' . CLOUD_FRONT_KEY_PAIR_ID;
  33. }


Функция использует следующие параметры и константы:
1. $url — это исходный URL вида http://example_sub_domain.cloudfront.net/images/image_1.jpg;
2. SECURE_URL_TIMEOUT — таймаут для URL в секундах;
3. CLOUD_FRONT_KEY_PAIR_PATH — путь к Вашему приватному ключу, который можно сгенерировать на странице Security Credentials во вкладке Key Pairs;
4. CLOUD_FRONT_KEY_PAIR_ID — идентификатор приватного ключа, который можно найти там же где и сам ключ.

На выходе этой функции будет приватный URL, при помощи которого конечный пользователь, в отведенный ему таймаут, сможет получить доступ к контенту, который расположен в приватном Distribution-е.

Полезные ссылки


1. Amazon CloudFront — главная страница сервиса;
2. Developer Guide — подробное описание сервиса CloudFront;
3. API Reference — документация по REST API для сервиса CloudFront;
4. AWS SDK for PHP — PHP библиотека, которая содержит классы для работы со всеми сервисами Amazon-а. Очень полезная вещь;
5. Тестовый код — небольшой код, который я написал в процессе тестирования.

P.S.


Вот в принципе и все, что я хотел написать. Статья не претендует на полный гайд по использованию кастомных origin серверов для CloudFront, но надеюсь будет полезна тем, кому не нужен S3. Всем спасибо за внимание.
Tags:
Hubs:
+33
Comments30

Articles

Change theme settings