Привязка Amazon S3 к блогу на Ghost + SSL
Этот блог работает (на момент написания) внутри Docker контейнера. Привязка обеспечивает загрузку картинок в хранилище Amazon S3 вместо сохранения на локальном диске, поэтому контейнер остается stateless и ему плевать на перезагрузки и ребилды
За загрузку и получение картинок со сторонних сервисов в Ghost отвечают storage adapters. Я использую ghost-storage-adapter-s3 и это был мой первый опыт работы с AWS.
Что у нас получится
По завершению данные будут доступны по 3 httpS адресам. У меня это так:
- https://s3.eu-central-1.amazonaws.com/s3.blog.amd-nick.me/2019/01/vk_-102092477_456241563.png
- https://d13eyure4mvxeo.cloudfront.net/2019/01/vk_-102092477_456241563.png
- https://s3.amd-nick.me/2019/01/vk_-102092477_456241563.png
Обратите внимание, все ссылки работают по https:// (для работы с SSL нужны будут некоторые настройки). Как я понимаю, первая ссылка ведет напрямую на файл с S3 ведра в Франкф урте. Вторая — CDN (Нужен для поддержки SSL). Третья — CNAME алиас на вторую (Чтобы по красоте)
После загрузки изображения в пост, он автоматически будет загружен с тем же именем на Amazon S3, но удаляться таким же образом не будет (или не всегда)
Теория
Для меня было новым то, что S3 контейнеры, пути и объекты очень гибко настраиваются. Нужно будет настроить контейнер так, чтобы к нему был публичный точечный (только к файлам) рид онли доступ. По умолчанию контейнеры доступны для чтения и записи только владельцу и то через API. Через браузер файлы посмотреть не получится, пока не "расшарить их". Кстати и тут важно не наделать глупостей, ведь при неправильной настройке в худшем случае ваши файлы смогут удалить, а в лучшем будут видны все файлы в директории, а это не совсем безопасно
Такой точечный доступ мы настроим через 2 места:
- В настройках контейнера сделаем его публичным для чтения файлов, если известен путь
- Создадим "виртуального юзера AWS", которому дадим право на загрузку и удаление объекта. Это чисто мое название, как я это понимаю. В Amazon эта сущность называется IAM
Второе даст нам API ключ, который мы будем использовать в настройке S3 Storage Adapter. Даже если ключ "уведут", то не смогут причинить много ущерба хранилищу
Создаем хранилище (Bucket)
В консоли AWS на странице S3 жмем Create bucket. Делаем имя а-ля s3.site.com, регион почти любой, я выбрал Франкфурт (eu-central-1) и жмем сразу Create, не вдаваясь в подробности других страниц.
В properties самого контейнера включаем Static Website Hosting и запоминаем Endpoint адрес
Кстати, этот скриншот загрузился в S3
Допускаем публичный доступ к контейнеру (мы его ограничим)
Галочки быть не д олжно
Во вкладке Bucket policy сверху копируем значение ARN (У меня arn:aws:s3:::blat.test.com) и делаем примерно такую запись:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AddPerm",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::blat.test.com/*"
}
]
}
Теперь объекты доступны по ссылке любому, кто ее получит. Для проверки можете загрузить в контейнер картинку и в ее свойствах будет Object URL
Делаем IAM пользователя (Виртуальный юзер)
Как я писал, им будет пользоваться наш блог для загрузки и удаления объектов, но у него не будет массовых действий, чтобы не навредить всему и вся
Сначала заходим на IAM > Policies > Create policy, где создадим "тип" прав доступа, который мы присвоим нашему IAM юзеру. На странице сразу переходим на вкладку json и, замен ив в двух местах ARN, вставляем такое:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::blat.test.com"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:PutObjectVersionAcl",
"s3:DeleteObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::blat.test.com/*"
}
]
}
Сохраняем с любым именем, например s3-access-for-ghost-to-blat
, чтобы понимать, что эта policy применима только к одному контейнеру_
Теперь создаем юзера с этими правами. Заходим на страницу IAM > Users, жмем Add user, даем ему опять же любое имя, например, традиционное ghost-blat, ставим галочку "Programmatic access" и давим кнопку Next, где делаем attach нашей policy
Находим нашу policy на 3 вкладке, ставим возле нее галочку
Скипаем 3 и 4 вкладку, на 5 нам дадут наш Access key и Secret, как логин и пароль, с которым блог сможет работать с нашим S3 контейнером. Не забудьте сохранить до нажатия на Close. Они будут использоваться для настройки плагина
Делаем, чтобы файлы были доступны по SSL
Если ваш сайт работает по http:// без SSL, то можете сразу переходить к установке и настройке плагина.
Я хочу, чтобы мои картинки были доступны по httpS://, а сделать это по-простому можно было только через Amazon CloudFront
CloudFront это штука, которую можно прицепить к контейнеру и настроить CDN. CDN нам не нужна, а вот возможность настроить SSL для его эндпоинтов очень даже кстати. К тому же амазон умеет подписывать свои SSL. Прям как Lets Encrypt, но для корпов
Идем сюда, выбираем WEB. Видим кучу настроек. Часть из них:
- Origin Domain Name : адрес, который был выдан нашему S3 контейнеру, когда мы включили Static Website Hosting. При нажатии оно предложит его
- Origin Path это как "под путь". Путь к той папке, которую мы хотим считать корнем при доступе через домен. Я оставил пустым
- Restrict Bucket Access запретит доступ к файлам по ссылке с S3 и они будут доступны только через CloudFront. Я оставил
- Viewer Protocol Policy у меня редирект на https://
- Allowed HTTP Methods Get, Head достаточно
- Price Class выбрал чем поменьше, ибо мне вообще CDN не нужен
- Alternate Domain Names (CNAMEs) вот это очень интересный пункт. Если у вас свой домен и вы определились, по какому поддомену будут доступны ваши файлы, то укажите его здесь. Что-то вроде s3.test.com
- SSL Certificate. Если вы указали CNAME, тогда тут нужно переключить кнопку и сгенерировать сертификат. У меня тут была проблема , потому что я пытался сгенерировать сертификаты в eu-central-1, а оказалось, что их нельзя здесь использовать. Пришлось писать в поддержку, чтобы расширили лимит для us-east-1
Уже сейчас CloudFront выдал вам адрес, по которому доступны файлы контейнера по http://. Для проверки подставьте Domain Name, выданный клаудфронтом вместо домена, который выдался в Static Website Hosting
In Progress, но файлы уже доступны по адресу из 3 колонки, если приставить полный путь к файлу
Осталось открыть панель управления DNS записями вашего домена и добавить там CNAME (зеркало) запись с именем, указанным в Alternative Domain Names. В значение записи укажите Domain Name, который выдал CloudFront.
Установка и настройка адаптера
Она хорошо описана на странице репозитория проекта, там ничего сложного. Мой конфиг выглядит примерно так:
Я долго не вдуплял только что ввести в DEFAULT_REGION, остальное как-то понял
В S3_ASSET_HOST указываем имя той самой CNAME записи с https:// или адрес, выданный CloudFront, если не делали свой поддомен
Задавайте вопросы, всем отвечу. Почитать еще всякие интересности можно у меня в t.me/uFeed