AWS / Cloud · Architecture / CI-CD
Déployer une distribution CloudFront avec une origine S3 privée
Configurer Origin Access Control et HTTPS puis vérifier l’accès par CloudFront et le refus d’accès direct à S3.
Pour préparer une origine privée, mettez en place S3 et OAC, vérifiez un objet connu puis préparez le domaine public. Disposez d’un accès AWS autorisé, de curl, du bucket et de sa région, d’une clé existante, du domaine technique CloudFront et d’un certificat ACM ISSUED en us-east-1 couvrant l’alias.
1. Définir le résultat attendu
Le navigateur doit accéder au site en HTTPS par CloudFront. Le bucket S3 ne doit pas servir les objets à un visiteur anonyme en accès direct. Pendant la préproduction, le nom public ne pointe pas encore vers la nouvelle distribution.
Le chemin de requête est simple : le visiteur rejoint CloudFront; CloudFront lit l’objet dans le bucket privé avec une Origin Access Control (OAC). Une bucket policy autorise s3:GetObject au principal CloudFront seulement pour l’ARN de la distribution attendue. Le rôle de publication, lui, suit un chemin distinct pour écrire les fichiers.
Dans ce projet, la distribution utilise une origine S3 standard plutôt qu’un endpoint « S3 website », car OAC ne protège pas un endpoint de site web. Une CloudFront Function transforme les chemins terminés par / en chemin index.html, par exemple /articles/ en /articles/index.html.
2. Garder le DNS hors du premier déploiement
Déployez une distribution propre au portfolio sans modifier la distribution historique de dev.lucat.dev. Le certificat et la Hosted Zone existent déjà; les enregistrements DNS restent hors de ce premier déploiement.
Dans le template du site, EnableDnsRecords contrôle les alias Route 53. Sa valeur par défaut est false. Avant d’exécuter un Change Set initial, inspectez les changements attendus : dans la recette initiale, il s’agissait de créer le bucket, sa policy, la distribution et la CloudFront Function, sans record DNS.
3. Construire l’origine privée
Le bucket active le blocage des accès publics, impose BucketOwnerEnforced et chiffre les objets au repos avec SSE-S3. Les protections Retain et UpdateReplacePolicy limitent le risque de perte de données si CloudFormation supprime ou remplace la ressource. Elles impliquent aussi qu’un retrait futur doit traiter explicitement le bucket conservé.
La bucket policy donne seulement s3:GetObject au service CloudFront et restreint cette autorisation avec AWS:SourceArn à la distribution du portfolio. Elle ne donne pas à CloudFront le droit d’écrire. Vérifiez donc séparément les deux chemins : le lecteur CloudFront doit obtenir l’objet; l’accès anonyme direct à S3 doit être refusé.
L’OAC du portfolio est créée par la stack bootstrap puis importée par la stack du site. Ce choix garde la création, la modification et la suppression de l’OAC en dehors du rôle CloudFormation du site. Le rôle du site conserve la lecture nécessaire à la configuration de la distribution. Cette frontière évite de lui accorder des opérations plus larges qui pourraient toucher l’OAC de dev.lucat.dev.
4. Configurer CloudFront et TLS
La distribution relie le bucket régional à l’OAC importée. Son comportement n’autorise que GET et HEAD, redirige HTTP vers HTTPS et utilise le certificat ACM associé à lucat.dev. Le certificat utilisé par CloudFront doit être dans us-east-1; avant le déploiement, le statut ISSUED et les noms couverts doivent correspondre au domaine.
Inspectez aussi l’alias de domaine et la version minimale TLS dans le Change Set et la configuration déployée. L’alias permet à CloudFront de présenter le certificat attendu lorsque la requête conserve le nom lucat.dev. Il ne crée pas à lui seul d’enregistrement DNS.
5. Recetter le point d’entrée sans modifier le DNS
curl --connect-to conserve le nom d’hôte de l’URL pour TLS et l’en-tête Host, tout en ouvrant la connexion vers le domaine technique CloudFront. Cela permet de tester l’alias avant de faire pointer Route 53 vers lui. Remplacez le placeholder par le domaine de votre distribution :
curl --fail --show-error --silent --connect-to "lucat.dev:443:<distribution>.cloudfront.net:443" --output /dev/null --write-out '%{http_code}\n' "https://lucat.dev/smoke/"
Pour contrôler la redirection HTTP, observez le statut et Location avec une requête HEAD :
curl --head --connect-to "lucat.dev:80:<distribution>.cloudfront.net:80" "http://lucat.dev/smoke/"
La clé /smoke/index.html doit être connue et présente dans le bucket. Comparez la lecture CloudFront avec une requête anonyme sur le même objet à l’endpoint REST S3 régional :
curl --head "https://<bucket>.s3.<region>.amazonaws.com/smoke/index.html"
Remplacez bucket et région par ceux de l’origine. Un 200 CloudFront confirme la lecture de cet objet avec le nom TLS attendu. Un 403 direct indique le refus de cette requête anonyme dans ce contexte; il ne prouve pas à lui seul l’absence de tout accès public. Une clé inexistante peut aussi produire 403 selon les permissions. Inspectez séparément bucket policy, blocage des accès publics et OAC. Utilisez l’endpoint REST, pas un endpoint S3 website auquel OAC ne s’applique pas.
Le 27 septembre 2026, j’ai déployé la stack lucat-portfolio-prod, qui est passée à l’état CREATE_COMPLETE. La distribution était Deployed et activée. La page /smoke/index.html répondait HTTP 200 en HTTPS, HTTP redirigeait vers HTTPS, la lecture S3 directe répondait HTTP 403 et la zone Route 53 ne contenait pas d’enregistrement A/AAAA pour l’apex.
Cette recette décrit l’accès initial à l’objet smoke et à l’origine S3. Depuis cette étape, le portfolio Astro a été déployé sur cette infrastructure et est accessible à l’adresse lucat.dev.
6. Publier puis vérifier le site
Construire le paquet à partir des routes approuvées puis vérifier l’artifact avant sa publication. Après publication, visiter les pages via le domaine CloudFront sans DNS public et contrôler les routes attendues, les liens internes, les images, les fichiers, les redirections et les en-têtes de préproduction.
Le pipeline local du projet sépare le build approuvé de la publication. La publication manuelle reçoit l’artifact précis du build et vérifie son manifeste avant synchronisation. Le préfixe /smoke/ est préservé.
7. Préparer la bascule DNS
Avant toute bascule, vérifiez l’état actuel des A et AAAA de l’apex. Une entrée existante impose de comprendre la cible et de préparer sa migration; ne la remplacez pas implicitement. Relisez ensuite le Change Set DNS. Le garde-fou du projet attend exactement deux ajouts, A et AAAA, pour lucat.dev; toute suppression, modification, remplacement ou ressource inattendue arrête la procédure.
Avant la bascule, vérifier que le site est servi par CloudFront avec le nom et le certificat prévus. Le Change Set doit montrer uniquement les deux alias attendus et la zone doit être relue juste avant l’exécution.
8. Contrôler après la bascule
Après l’exécution autorisée du changement DNS, vérifiez la résolution A/AAAA puis les parcours du site par le nom public : HTTPS, redirection HTTP, pages, assets et liens. --connect-to teste la distribution avec le nom TLS attendu avant la bascule; la résolution publique se vérifie après la modification DNS.
OAC protège l’accès à l’origine; les visiteurs accèdent au site par le domaine CloudFront. AWS recommande le comportement de signature always pour l’OAC.