web-dev-qa-db-fra.com

Obtention de 403 (interdit) lors du chargement du fichier AWS CloudFront

Je travaille sur une application vidéo et je stocke les fichiers sur AWS S3. L'utilisation de l'URL par défaut, telle que https://***.amazonaws.com/***, fonctionne bien, mais j'ai décidé d'utiliser CloudFront, qui est plus rapide pour la diffusion du contenu.

En utilisant CF, je continue à obtenir 403 (Forbidden) en utilisant cette URL https://***.cloudfront.net/***. Est-ce que j'ai manqué quelque chose?

Tout fonctionne bien jusqu'à ce que je décide de charger le contenu de CloudFront qui pointe vers mon compartiment.

Une solution s'il vous plaît?

13
Shina

Lorsque vous limitez l'accès au contenu S3 à l'aide d'une stratégie de compartiment qui inspecte l'en-tête Referer: entrant, vous devez créer un peu de configuration personnalisée pour "déjouer" CloudFront.

Il est important de comprendre que CloudFront est conçu pour être un cache bien conçu. Par "bien comporté", je veux dire que CloudFront est conçu pour ne jamais renvoyer une réponse différente de celle que le serveur Origin aurait renvoyée. Je suis sûr que vous pouvez voir que c'est un facteur important.

Supposons que j'ai un serveur Web (pas S3) derrière CloudFront et que mon site Web est conçu pour renvoyer un contenu différent en fonction de l'inspection de l'en-tête Referer: ... ou de tout autre en-tête de requête http, tel que User-Agent: par exemple. En fonction de votre navigateur, je pourrais renvoyer un contenu différent. Comment CloudFront pourrait-il savoir cela, de manière à éviter de servir à l'utilisateur la mauvaise version d'une page donnée?

La réponse est, il ne serait pas capable de dire - il ne peut pas savoir cela. La solution de CloudFront n’est donc pas de transférer la plupart des en-têtes de requête à mon serveur. Ce que mon serveur Web ne peut pas voir, il ne peut pas réagir. Le contenu que je renvoie ne peut donc pas varier en fonction des en-têtes que je ne reçois pas, ce qui empêche CloudFront de mettre en cache et de renvoyer la mauvaise réponse, en fonction de ces en-têtes. Les caches Web ont l'obligation d'éviter de renvoyer le contenu mis en cache incorrect pour une page donnée.

"Mais attendez", vous objectez. "Mon site dépend de la valeur d'un en-tête donné afin de déterminer comment répondre." C'est logique, il faut donc dire à CloudFront:

Au lieu de mettre en cache mes pages en me basant uniquement sur le chemin demandé, il vous faut également transférer le Referer: ou le User-Agent: ou l'un des autres en-têtes envoyés par le navigateur, et mettre en cache la réponse pour pouvoir l'utiliser sur d'autres requêtes incluant non seulement le même chemin, mais aussi les mêmes valeurs pour le ou les en-têtes supplémentaires que vous m'avez transmis.

Toutefois, lorsque le serveur d'origine est S3, CloudFront ne prend pas en charge le transfert de la plupart des en-têtes de requête, en supposant que le contenu statique ne pouvant pas varier, ces en-têtes lui imposeraient simplement de mettre en cache plusieurs réponses identiques inutilement.

Votre solution n'est pas d'indiquer à CloudFront que vous utilisez S3 en tant qu'origine. Au lieu de cela, configurez votre distribution pour utiliser une origine "personnalisée" et donnez-lui le nom d'hôte du compartiment à utiliser comme nom d'hôte du serveur d'origine.

Ensuite, vous pouvez configurer CloudFront pour qu'il transmette l'en-tête Referer: à Origin et votre stratégie de compartiment S3 qui refuse/autorise les demandes basées sur cet en-tête fonctionnera comme prévu.

Eh bien, presque comme prévu. Cela réduira quelque peu votre taux d'accès au cache, car désormais les pages mises en cache seront mises en cache sur la base du chemin et de la page de référence. Si un objet S3 est référencé par plusieurs pages de votre site, CloudFront mettra en cache une copie pour chaque demande unique. Cela ressemble à une limitation, mais en réalité, il ne s'agit que d'un artefact du comportement correct du cache: tout ce qui est transmis au serveur principal doit être utilisé pour déterminer si cette réponse est utilisable pour le traitement des demandes futures.

Voir http://docs.aws.Amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesForwardHeaders pour configurer CloudFront avec des en-têtes spécifiques à envoyer à votre serveur Origin.

Important: ne transférez pas les en-têtes dont vous n’avez pas besoin, car chaque demande de variante réduit davantage votre taux de réussite. En particulier lorsque vous utilisez S3 en tant que back-end pour une origine personnalisée, ne transférez pas l'en-tête Host:, car cela ne va probablement pas répondre à vos attentes. Sélectionnez l'en-tête Referer: ici et testez. S3 devrait commencer à voir l'en-tête et à réagir en conséquence.

Notez que lorsque vous avez supprimé votre stratégie de compartiment à des fins de test, CloudFront aurait continué à servir la page d'erreur mise en cache, sauf si vous avez vidé votre cache en envoyant une demande d'invalidation, ce qui a pour effet que CloudFront purge toutes les pages mises en cache correspondant au modèle de chemin spécifié, au cours du cours. d'environ 15 minutes. La chose la plus simple à faire lors des expérimentations consiste à créer une nouvelle distribution CloudFront avec la nouvelle configuration, car les distributions elles-mêmes sont gratuites.

Lorsque vous affichez les en-têtes de réponse de CloudFront, notez les réponses X-Cache: (hit/miss) et Age: (depuis combien de temps cette page a été mise en cache). Celles-ci sont également utiles pour le dépannage. 


Update: _ ​​= @alexjs [] a fait une observation importante: au lieu de le faire, utilisez la stratégie de compartiment et transmettez l'en-tête Referer: à S3 pour analyse, ce qui affectera le taux de cache dans une mesure qui varie en fonction de la répartition des ressources sur les pages de renvoi - vous pouvez utiliser le nouveau service AWS Web Application Firewall, qui vous permet d'imposer des règles de filtrage des demandes entrantes à CloudFront, afin d'autoriser ou de bloquer les demandes en fonction de chaîne correspondant aux en-têtes de demande .Pour cela, vous devez connecter la distribution à S3 en tant qu’origine S3 (la configuration normale, contrairement à ce que j’ai proposé dans la solution ci-dessus, avec une origine "personnalisée") et utiliser la fonctionnalité intégrée de CloudFront pour: authentifiez les requêtes back-end auprès de S3 (afin que le contenu du compartiment ne soit pas directement accessible si un acteur malveillant le demande à S3).

Voir https://www.alexjs.eu/preventing-hotlinking-using-cloudfront-waf-and-referer-checking/ pour plus d'informations sur cette option.

See https://www.alexjs.eu/preventing-hotlinking-using-cloudfront-waf-and-referer-checking/ for more on this option.

10
Michael - sqlbot

En outre, cela peut être quelque chose de simple. Lorsque vous téléchargez pour la première fois un fichier dans un compartiment S3, il est non public, même si les autres fichiers de ce compartiment sont publics et même si le compartiment lui-même est public. 

Pour changer cela dans la AWS Console, cochez la case en regard du dossier que vous voulez rendre public (le dossier que vous venez de télécharger), puis choisissez "Rendre public" dans le menu. 

Les fichiers de ce dossier (et de tous les sous-dossiers) seront rendus publics et vous pourrez les servir à partir de S3.

Pour l'AWS CLI, ajoutez l'option "--acl public-read" dans votre commande, comme suit:

aws s3 cp index.html s3://your.remote.bucket --acl public-read
4
Patrick Chu

En ce qui me concerne, j’avais donné à CodePipeline l’accès à S3, ce qui a remplacé ma stratégie de compartiment s3. Par exemple, quelque chose comme ceci: 

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::mys3bucket/*"
        }
    ]
}
0
Jghorton14