Корректная конфигурация S3 + Cloudfront CORS?
Мое приложение хранит изображения на S3, а затем передает их через Cloudfront. Я рад использовать новую поддержку S3 CORS, чтобы я мог использовать методы холста HTML5 (которые имеют перекрестную политику происхождения), но, похоже, не могу правильно настроить мой S3 и Cloudfront. При попытке преобразовать изображение в элемент холста все еще работает сообщение "Uncaught Error: SECURITY_ERR: DOM Exception 18".
Вот что у меня так далеко:
S3
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>MY_WEBSITE_URL</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
<CORSRule>
<AllowedOrigin>MY_CLOUDFRONT_URL</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
CloudFront
происхождения
Origin Protocol Policy: Match Viewer
HTTP Port: 80
HTTPS Port: 443
поведения
Origin: MY_WEBSITE_URL
Object Caching: Use Origin Cache Headers
Forward Cookies: None
Forward Query Strings: Yes
Есть что-то, чего я здесь не хватает?
ОБНОВЛЕНИЕ: Просто попытался изменить заголовки на
<AllowedHeader>Content-*</AllowedHeader>
<AllowedHeader>Host</AllowedHeader>
на основе этого вопроса Amazon S3 CORS (Cross-Origin Resource Sharing) и Firefox междоменная загрузка шрифтов
Все еще не идти.
ОБНОВЛЕНИЕ: БОЛЬШЕ ИНФОРМАЦИИ ПО ЗАПРОСУ
Request
URL:https://d1r5nr1emc2xy5.cloudfront.net/uploaded/BAhbBlsHOgZmSSImMjAxMi8wOS8xMC8xOC81NC80Mi85NC9ncmFzczMuanBnBjoGRVQ/32c0cee8
Request Method:GET
Status Code:200 OK (from cache)
ОБНОВИТЬ
Я думаю, что мой запрос был неверным, поэтому я попытался включить CORS с
img.crossOrigin = '';
но затем изображение не загружается, и я получаю сообщение об ошибке: загрузка образа из разных источников запрещена политикой общего доступа к ресурсам из разных источников.
10 ответов
26 июня 2014 года AWS выпустила корректное поведение Vary: Origin в CloudFront, так что теперь вы просто
Установите конфигурацию CORS для вашей корзины S3, включая
* AllowedOrigin> В CloudFront -> Распределение -> Поведения для этого источника используйте параметр "Прямые заголовки: белый список" и белый список заголовка "Источник".
Подождите ~20 минут, пока CloudFront распространит новое правило
Теперь ваш дистрибутив CloudFront должен кэшировать разные ответы (с соответствующими заголовками CORS) для разных заголовков клиента Origin.
Чтобы дополнить ответ @ Бретта. Есть страницы документации AWS, подробно описывающие CORS на CloudFront и CORS на S3.
Шаги подробно описаны ниже:
- В вашем S3 ведро перейдите в Разрешения -> Конфигурация CORS
- Добавить правила для CORS в редакторе
<AllowedOrigin>
Правило является важным. Сохраните конфигурацию. - В вашем дистрибутиве CloudFront перейдите к Поведению -> выберите поведение -> Изменить
- В зависимости от того, хотите ли вы
OPTIONS
кешируются ответы или нет, согласно AWS есть два пути:
- Если вы хотите, чтобы ответы OPTIONS кэшировались, сделайте следующее:
- Выберите параметры для параметров поведения кэша по умолчанию, которые включают кэширование для ответов OPTIONS.
- Сконфигурируйте CloudFront для пересылки следующих заголовков: Origin, Access-Control-Request-Headers и Access-Control-Request-Method.
- Если вы не хотите, чтобы ответы OPTIONS кэшировались, настройте CloudFront для пересылки заголовка Origin вместе с любыми другими заголовками, требуемыми вашим источником
И с этим CORS из CloudFront с S3 должен работать.
2022 ответ:
- Перейдите в свою корзину S3 -> Разрешения
- Прокрутите вниз до совместного использования ресурсов между источниками (CORS).
- Применить политику:
[
{
"AllowedHeaders": [],
"AllowedMethods": [
"GET"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]
Это позволит получить запрос GET из всех источников. Измените в соответствии с потребностями вашего проекта.
Перейдите в свой дистрибутив CloudFront -> Behaviors -> Edit (в моем случае у меня было только одно Behavior)
Прокрутите вниз до пункта Кэшировать ключ и исходные запросы.
Выберите политику кэширования и политику запроса источника (рекомендуется)
В разделе « Политика запроса источника» — необязательно выберите CORS-CustomOrigin.
Сохранить изменения
Сделанный!
Март 2023 г. — меня это устраивает.
Конфигурация сегмента S3
Политика совместного использования ресурсов между источниками (CORS) для корзины S3 (сведения о корзине > разрешения). РегулироватьAllowedOrigins
,AllowedHeaders
для вашего проекта (вы можете использовать*
во время тестирования установки).
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"HEAD"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]
Конфигурация Cloudfront CDN
Перейдите в Дистрибутив Cloudfront > Изменить поведение (в большинстве случаев для каждого дистрибутива существует только один вариант).
ОБНОВЛЕНИЕ: это больше не верно с недавними изменениями в CloudFront. Yippee! Смотрите другие ответы для деталей. Я оставляю это здесь для контекста / истории.
проблема
CloudFront не поддерживает CORS 100%. Проблема в том, как CloudFront кэширует ответ на запрос. Любой другой запрос того же URL-адреса после этого приведет к кешированию запроса независимо от источника. Ключевой частью этого является то, что он включает в себя заголовки ответа от источника.
Первый запрос до того, как CloudFront что-нибудь кэширует Origin: http://example.com
имеет заголовок ответа:
Access-Control-Allow-Origin: http://example.com
Второй запрос от Origin: https://example.com
(обратите внимание, что это HTTPS, а не HTTP) также имеет заголовок ответа:
Access-Control-Allow-Origin: http://example.com
Потому что это то, что CloudFront кэшировал для URL. Это неверно - консоль браузера (по крайней мере, в Chrome) покажет сообщение о нарушении CORS, и все будет сломано.
Временное решение
Предлагаемый обходной путь - использовать разные URL для разных источников. Хитрость заключается в том, чтобы добавить уникальную строку запроса, которая отличается, так что есть одна кэшированная запись на источник.
Так что наши URL будут примерно такими:
http://.../some.png?http_mysite.com
https://.../some.png?https_mysite.com
Это работает, но любой может заставить ваш сайт работать плохо, меняя строки запросов. Это вероятно? Наверное, нет, но отладка этой проблемы - огромная проблема.
Правильный обходной путь - не использовать CloudFront с CORS, пока они полностью не поддерживают CORS.
На практике
Если вы используете CloudFront для CORS, используйте альтернативный метод, который будет работать, когда CORS не работает. Это не всегда вариант, но сейчас я динамически загружаю шрифты с помощью JavaScript. Если основанный на CORS запрос к CloudFront завершается неудачно, я возвращаюсь к серверному прокси-серверу для шрифтов (не для перекрестного источника). Таким образом, вещи продолжают работать, хотя CloudFront каким-то образом получил плохую кешированную запись для шрифта.
Я следовал документации AWS:
Затем я использовал aws cdk, чтобы сделать это за меня. Полный источник здесь: https://github.com/quincycs/quincymitchell.com
const myBucket = new Bucket(this, 'bucket', {
bucketName: `prod-${domainName}`,
cors: [{
allowedMethods: [HttpMethods.GET],
allowedOrigins: ['*'],
allowedHeaders: ['*']
}],
enforceSSL: true,
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
removalPolicy: RemovalPolicy.RETAIN
});
const mycert = Certificate.fromCertificateArn(this, 'certificate', ssmCertArn);
new Distribution(this, 'myDist', {
defaultBehavior: {
origin: new S3Origin(myBucket),
viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
originRequestPolicy: OriginRequestPolicy.CORS_S3_ORIGIN,
responseHeadersPolicy: ResponseHeadersPolicy.CORS_ALLOW_ALL_ORIGINS,
allowedMethods: AllowedMethods.ALLOW_GET_HEAD_OPTIONS, // needed for cors
cachedMethods: CachedMethods.CACHE_GET_HEAD_OPTIONS, // needed for cors
},
defaultRootObject: 'index.html',
domainNames: [domainName, `www.${domainName}`],
certificate: mycert
});
В завершение предыдущего ответа я хотел бы поделиться с AWS шагами по включению CORS. Я нашел это очень полезным, предоставив дополнительные ссылки: https://aws.amazon.com/premiumsupport/knowledge-center/no-access-control-allow-origin-error/
Кроме того, при тестировании изменений, помимо задержки развертывания CloudFront, следует учитывать кеш браузера. Я предлагаю использовать разные сеансы инкогнито при тестировании ваших изменений.
Публикация некоторых нетривиальных конфигураций, которые я сделал, чтобы заставить его работать:
- Назначьте пользовательский домен облачному интерфейсу, чтобы пользовательский домен был поддоменом, из которого будет запускаться интерфейс вашего приложения. В случае OP он использует localhost:3000; скорее всего, он тестирует свою настройку разработчика, но он должен развернуть это приложение в каком-то домене: назовем это «myapp.com». Таким образом, он может назначить собственный домен, например cdn.myapp.com, чтобы он указывал на blah.cloudfront.net. Вам нужно будет создать / импортировать собственный сертификат SSL для нового личного домена; сертификат облачного интерфейса по умолчанию не будет работать. См. Это: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CNAMEs.html[![введите описание изображения здесь] ]22У первого нет личного домена, поэтому столбец CNAME пуст. У второго есть собственный домен, поэтому он у нас напечатан. Вы можете убедиться, что таким образом ваш личный домен был направлен на распространение облачного интерфейса.
- Поведение Cloudfront: я предполагаю, что вы уже настроили группу доверенных ключей, поскольку на данный момент у вас уже есть подписанный файл cookie. ОДНАКО, вам нужно будет создать собственную политику кеширования и политику запросов происхождения. См. Следующие снимки экрана с настраиваемой политикой кеширования:и Политикой запроса источника . Следует отметить, что вам необходимо внести в белый список эти заголовки: Origin, Access-Control-Request-Method, Access-Control-Allow-Origin, Access-Control-Запрос-Заголовки. (Вы могли заметить, что Access-Control-Allow-Origin отсутствует в раскрывающемся списке; просто введите его!). Также разрешите все файлы cookie.
- Конфигурация S3 CORS: перейдите в корзину S3 и щелкните вкладку разрешений. Прокрутите вниз до конфигурации CORS. Отказ от ответственности: я просто вставил то, что у меня сработало. Обоснованием этого было то, что в моем сценарии к этому S3 должен был получить доступ либо CDN, либо приложение. Я попытался поставить «*» снисходительно, но политика CORS в Chrome жаловалась на то, что я не могу использовать подстановочную запись в AllowedOrigins!
[ { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "PUT", "POST", "GET", "HEAD", "DELETE" ], "AllowedOrigins": [ "cdn.myapp.com", "myapp.com", "https://cdn.myapp.com", "https://myapp.com" ], "ExposeHeaders": [ "ETag" ] } ]
- react-player: я использую response-player, как это (обратите внимание на то, что параметр forceHLS установлен, но он снова специфичен для моего варианта использования. Я думаю, что это не обязательно в целом)
<ReactPlayer className="react-player" url={url} controls={controls} light={light} config={ { file: { forceHLS: true, hlsOptions: { xhrSetup: function (xhr, url) { xhr.withCredentials = true; // send cookies }, }, }, } } playIcon={<PlayIcon />} width="100%" height="100%" />
Не совсем уверен, в чем ваша проблема, но:
https://forums.aws.amazon.com/thread.jspa?messageID=377513
ответил на некоторые мои проблемы с CORS, S3 и Cloudfront.
Я также обнаружил, что некоторые ресурсы внутри корзины будут возвращаться с правильными заголовками CORS, а некоторые - нет. После аннулирования ресурсов все они вернулись с правильными заголовками, не зная, почему некоторые нуждались в аннулировании, а другие - нет, поскольку они были загружены в одно и то же время, того же типа, то же самое ведро:(
Дополнительной причиной ошибок CORS может быть перенаправление HTTP на HTTPS, настроенное в CloudFront.
Согласно документации, в запросах CORS не разрешены перенаправления на другой источник .
Например, если вы попытаетесь получить доступ к некоторому URL-адресу http://example.com, который имеет правило облачного интерфейса для перенаправления HTTP на HTTPS, вы получите ошибку CORS, поскольку https : //cloudfront.url рассматривается браузером как другое происхождение.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSExternalRedirectNotAllowed