Optimiser le comportement d'Amazon Cloudfront pour des sites web via des Cloudfront Fonctions (application avec Gatsby)
6 min read
Gatsby est un outil permettant de créer rapidement des sites webs en utilisant le langage React, du javascript ou le langage TypeScript.
Cet outil permet de facilement déployer le site sur Amazon S3 et d'ainsi réduire la complexité de maintenance et les coûts. Pour assurer une distribution du contenu rapide et efficace, nous utilisons Amazon Cloudfront.
Installer le plugin Gatsby S3
> yarn add gatsby-plugin-s3 ou > npm install gatsby-plugin-s3
Modifier gatsby-config.js
Il faut ajouter la configuration du plugin dans ce fichier. Il est nécessaire de préciser à minima le bucket de destination.
plugins: [ { resolve: `gatsby-plugin-s3`, options: { bucketName: "myBucket", }, }, ]
Problème identifié
Si nous tentons de nous connecter directement sur une page autre que la page d'accueil, nous obtenons le résultat suivant :
wget https://sylvain.bruas.fr/blog/aws-eks-contrainte-ip/ --2023-10-30 15:18:32-- https://sylvain.bruas.fr/blog/aws-eks-contrainte-ip/ Résolution de sylvain.bruas.fr (sylvain.bruas.fr)… 52.222.144.106, 52.222.144.45, 52.222.144.68, ... Connexion à sylvain.bruas.fr (sylvain.bruas.fr)|52.222.144.106|:443… connecté. requête HTTP transmise, en attente de la réponse… 403 Forbidden 2023-10-30 15:18:32 erreur 403 : Forbidden.
La solution proposée par Gatsby est d'utiliser S3 avec l'option Static Website Hosting et configurer le bucket en public-read. Dans cette configuration, le bucket peut être accédé directement, en HTTP si l'on trouve son URL.
Une autre solution est disponible depuis la mise en place des Lambda@Edge (2016) et des Cloudfront functions (2021). En utilisant l'un de ces deux outils, nous pouvons manipuler la requête HTTP entrante, et si l'on identifie une URL terminant par un slash (/) ou qui ne contient pas d'extension nous ajoutons à la fin '/index.html'.
Lambda@edge et Cloudfront Functions
Nous allons donc déployer le code suivant, tiré de la documentation AWS.
function handler(event) { var request = event.request var uri = request.uri // Check whether the URI is missing a file name. if (uri.endsWith("/")) { request.uri += "index.html" } // Check whether the URI is missing a file extension. else if (!uri.includes(".")) { request.uri += "/index.html" } return request }
Il ne reste plus qu'à choisir entre Lambda@Edge et Cloudfront Functions. L'article annoncant la mise à disposition de Cloudfront fonction nous renseigne clairement sur les différences principales entre ces 2 services.
CloudFront Functions Lambda@Edge Runtime support JavaScript Node.js, Python Execution location Edge Locations (~220) Regional Edge Caches (~10) CloudFront triggers supported Viewer request, Viewer response Viewer request,Viewer response,Origin request, Origin response Maximum execution time 1 millisecond 5 seconds (viewer triggers) Total package size 10 KB 1 MB (viewer triggers) Maximum memory 2MB 128MB (viewer triggers) Network access No Yes File system access No Yes Access to the request body No Yes Pricing Free Tier* + $0.10 per 1 million invocations $0.60 per 1M requests + $0.00005001 for every GB-second Free Tier pour CloudFront Functions : 2,000,000 Invocations
Notre fonction javascript est très simple et légère. Elle s'exécute rapidement et ne consomme que de la mémoire, et en quantité limitée. Notre fonctionnalité peut donc être déployée sur les 2 services. C'est donc l'aspect financier qui va faire la différence.
Que ce soit pour les petits sites qui profiterons de l'offre gratuite, ou le prix à la requête pour les sites ayant un grand nombre de visite, Amazon Cloudfront Functions reste la solution la plus efficiente économiquement.
La suite de l'article et les exemples proposés se concentreront donc sur Amazon Cloudfront Functions.
Nous allons utiliser Terraform pour déployer notre fonction.
Déploiement de la solution
-
Nous créons un fichier index.js dans le chemin functions/cloudfront du projet.
function handler(event) { var request = event.request var uri = request.uri // Check whether the URI is missing a file name. if (uri.endsWith("/")) { request.uri += "index.html" } // Check whether the URI is missing a file extension. else if (!uri.includes(".")) { request.uri += "/index.html" } return request }
-
Nous ajoutons dans le répertoire iac un nouveau fichier appelé cloudfront_functions.tf. Voici son contenu :
resource "aws_cloudfront_function" "redirect-index" { name = "redirect-index" runtime = "cloudfront-js-1.0" comment = "add missing index.html at the end of url" publish = true code = file("../functions/cloudfront/index.js")}
Il faut bien veiller à préciser le moteur (runtime) à utiliser, publier la fonction et modifier si nécessaire le chemin vers notre code.
-
Ajouter le code suivant dans la définition terraform de votre distribution cloudfront, dans la section default_cache_behavior
default_cache_behavior = { function_association = { viewer-request = { function_arn = aws_cloudfront_function.redirect-index.arn } } ...
-
terraform plan
... Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_cloudfront_function.redirect-index will be created + resource "aws_cloudfront_function" "redirect-index" { + arn = (known after apply) + code = <<-EOT function handler(event) { var request = event.request; var uri = request.uri; // Check whether the URI is missing a file name. if (uri.endsWith('/')) { request.uri += 'index.html'; } // Check whether the URI is missing a file extension. else if (!uri.includes('.')) { request.uri += '/index.html'; } return request; } EOT + comment = "add missing index.html at the end of url" + etag = (known after apply) + id = (known after apply) + live_stage_etag = (known after apply) + name = "redirect-index" + publish = true + runtime = "cloudfront-js-1.0" + status = (known after apply) } Plan: 1 to add, 0 to change, 0 to destroy.
-
Terraform apply
L'affichage sera le même qu'à l'étape précédente. Une invite va apparaitre pour vous demander de valider que vous êtes prêt à appliquer ces modifications. Après quelques minutes d'attente, la fonction sera déployée.
-
Résultats
Avant la mise en place de la fonction, nous obtenions le résultat suivant, une erreur 403 :
wget https://sylvain.bruas.fr/blog/aws-eks-contrainte-ip/ --2023-10-30 15:18:32-- https://sylvain.bruas.fr/blog/aws-eks-contrainte-ip/ Résolution de sylvain.bruas.fr (sylvain.bruas.fr)… 52.222.144.106, 52.222.144.45, 52.222.144.68, ... Connexion à sylvain.bruas.fr (sylvain.bruas.fr)|52.222.144.106|:443… connecté. requête HTTP transmise, en attente de la réponse… 403 Forbidden 2023-10-30 15:18:32 erreur 403 : Forbidden.
Avec la fonction Cloudfront nous obtenons :
wget https://sylvain.bruas.fr/blog/aws-eks-contrainte-ip/ --2023-10-30 15:46:41-- https://sylvain.bruas.fr/blog/aws-eks-contrainte-ip/ Résolution de sylvain.bruas.fr (sylvain.bruas.fr)… 52.222.144.68, 52.222.144.56, 52.222.144.45, ... Connexion à sylvain.bruas.fr (sylvain.bruas.fr)|52.222.144.68|:443… connecté. requête HTTP transmise, en attente de la réponse… 200 OKTaille : 108929 (106K) [text/html] Sauvegarde en : « index.html » index.html 100%[=============================================>] 106,38K --.-KB/s ds 0,06s 2023-10-30 15:46:42 (1,72 MB/s) — « index.html » sauvegardé [108929/108929]
La requête est donc traitée ainsi :
Conclusion
Nous avons grace à Cloudfront functions mis en place une solution de réécriture d'url s'appliquant à toutes les urls de ce site. Cela permettra par exemple aux moteurs de recherche d'indexer toutes les pages, ce qui n'aurait pas été possible sans la fonction de réécriture des URLs.
Vous pouvez retrouver tous les exemples de code précédents sur le dépôt github suivant : https://github.com/sylvainbruas/demo
-
Sylvain BRUAS
Je suis architecte solution AWS depuis plus de 8 ans. J'interviens dans les grands groupes pour les aider dans leur transformation vers le cloud AWS.
Mes compétences principales sont les fondations AWS, le Dev(SecFin*)Ops et les containers.
AWS Community Builder et AWS Authorized Instructor depuis 2024