DevOps Elastic Hayway
Document

SUBSCRIBE TO GET FULL ACCESS TO THE E-BOOKS FOR FREE 🎁SUBSCRIBE NOW

Professional Dropdown with Icon

SUBSCRIBE NOW TO GET FREE ACCESS TO EBOOKS

AWSLesson 23 / 4710 min readUpdated September 13, 2026

CloudFront devant S3 (HTTPS et cache)

À la fin de ce tutoriel, vous servirez un site/objet S3 privé via CloudFront avec Origin Access Control (OAC), HTTPS sur le domaine *.cloudfront.net, et une invalidation de cache — pattern production 2026 (plus de bucket public website).

Niveau : Intermédiaire · Temps estimé : 60–75 min · Versions testées : CloudFront + S3 OAC 2026, AWS CLI v2 · Dernière vérification : 2026-09-11 · Bucket Region : ca-central-1 (CloudFront est global)

Slug : aws-cloudfront-s3 · Série : AWS Solutions Architect · Mot-clé SEO : CloudFront S3

← Précédent : S3 versioning · → Suivant : VPC fondations · Hub : Démarrer avec AWS

Publish : HOLD

Prérequis

  • Bucket S3 privé en ca-central-1 avec index.html (site statique en mode privé, ou nouveau bucket)
  • Profil CLI lab ; BPA strict (pas de policy publique)
  • Accepter ~15–30 min de déploiement CloudFront (propagation edge)
  • Budget d’alerte actif
export AWS_PROFILE=lab
export AWS_DEFAULT_REGION=ca-central-1
# PowerShell : $env:AWS_PROFILE='lab'; $env:AWS_DEFAULT_REGION='ca-central-1'
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
BUCKET="lab-${ACCOUNT_ID}-cdn"

Coût estimé lab (ca-central-1 bucket + CloudFront global, 2026) :

Élément Ordre de grandeur Remarque
Stockage S3 cents pour HTML Ko Bucket privé
CloudFront Free Tier 1 To / 10 M req (souvent) Lab = négligeable
Distribution idle faible hors FT Supprimez après le lab
Invalidations 1 000 paths/mois gratuits / + /index.html OK

Supprimez la distribution (disable → wait → delete) puis le bucket. Une distribution oubliée a un coût de base faible mais réel hors Free Tier.

Ce que nous allons construire

Utilisateur ──HTTPS──► CloudFront (PoP)
                         │ OAC
                         ▼
                      S3 bucket privé (ca-central-1)
                      └── index.html (Block Public Access ON)

(Schéma — alt : « CloudFront OAC vers bucket S3 privé ».)

CloudFront est un CDN global : les PoP (points of presence) cachent les objets près des utilisateurs. L’origine reste votre bucket en ca-central-1. OAC remplace l’ancien OAI : signature SigV4 des requêtes origin, bucket policy conditionnée sur l’ARN de votre distribution.

Étape 1 — Pourquoi pas le website endpoint public

Approche HTTPS Bucket Cache edge Recommandé prod
S3 website public Non natif Public Non Non
CloudFront + OAC Oui Privé Oui Oui
Ancien OAI Oui Privé Oui Legacy → migrer OAC

OAC signe les requêtes origin ; la bucket policy n’autorise que le service CloudFront de votre distribution. Repère examen SA : le website endpoint (s3-website-…) ne supporte pas OAC de la même façon — utilisez l’endpoint REST bucket.s3.region.amazonaws.com comme origin. BPA reste all true : la policy OAC n’est pas une policy « publique ».

Étape 2 — Bucket privé + objet

aws s3api create-bucket --bucket "$BUCKET" 
  --create-bucket-configuration LocationConstraint=ca-central-1 
  --region ca-central-1

aws s3api put-public-access-block --bucket "$BUCKET" 
  --public-access-block-configuration 
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

aws s3api put-bucket-ownership-controls --bucket "$BUCKET" 
  --ownership-controls 'Rules=[{ObjectOwnership=BucketOwnerEnforced}]'

mkdir -p /tmp/cdn && cat > /tmp/cdn/index.html <<'HTML'
<!DOCTYPE html><html lang="fr"><head><meta charset="utf-8" />
<title>CloudFront + S3 lab</title></head>
<body><h1>Servi via CloudFront OAC</h1>
<p>Bucket privé — ca-central-1</p></body></html>
HTML

aws s3 sync /tmp/cdn "s3://$BUCKET/" --region ca-central-1

Vérifiez qu’un curl direct sur l’URL objet S3 échoue (privé) — attendu. Taggez Project=lab pour Cost Explorer. BucketOwnerEnforced désactive les ACL objet : tout passe par IAM + bucket policy.

Étape 3 — Créer l’OAC

OAC_ID=$(aws cloudfront create-origin-access-control 
  --origin-access-control-config "
Name=lab-oac-${ACCOUNT_ID},
Description=Lab OAC S3,
SigningProtocol=sigv4,
SigningBehavior=always,
OriginAccessControlOriginType=s3" 
  --query 'OriginAccessControl.Id' --output text)

echo "$OAC_ID"

SigningBehavior=always force la signature de chaque requête origin. Conservez OAC_ID : il sera référencé dans la config de distribution. Un OAC peut être réutilisé par plusieurs distributions, mais en lab un OAC dédié simplifie le nettoyage.

Étape 4 — Distribution CloudFront (minimal)

Fichier dist-config.json (à générer dynamiquement) :

CALLER=$(date +%s)
cat > /tmp/dist-config.json <<EOF
{
  "CallerReference": "lab-$CALLER",
  "Comment": "lab-s3-oac",
  "Enabled": true,
  "DefaultRootObject": "index.html",
  "Origins": {
    "Quantity": 1,
    "Items": [{
      "Id": "s3-origin",
      "DomainName": "${BUCKET}.s3.ca-central-1.amazonaws.com",
      "S3OriginConfig": { "OriginAccessIdentity": "" },
      "OriginAccessControlId": "${OAC_ID}"
    }]
  },
  "DefaultCacheBehavior": {
    "TargetOriginId": "s3-origin",
    "ViewerProtocolPolicy": "redirect-to-https",
    "AllowedMethods": {
      "Quantity": 2,
      "Items": ["GET", "HEAD"],
      "CachedMethods": { "Quantity": 2, "Items": ["GET", "HEAD"] }
    },
    "Compress": true,
    "ForwardedValues": {
      "QueryString": false,
      "Cookies": { "Forward": "none" }
    },
    "MinTTL": 0,
    "DefaultTTL": 3600,
    "MaxTTL": 86400
  },
  "PriceClass": "PriceClass_100"
}
EOF

DIST_ID=$(aws cloudfront create-distribution 
  --distribution-config file:///tmp/dist-config.json 
  --query 'Distribution.Id' --output text)

DOMAIN=$(aws cloudfront get-distribution --id "$DIST_ID" 
  --query 'Distribution.DomainName' --output text)

echo "DIST_ID=$DIST_ID DOMAIN=$DOMAIN"

Si l’API refuse le combo S3OriginConfig vide + OAC, utilisez la console : Origin domain = bucket, Origin access = Origin access control settings (recommended), create/select OAC. Notez DIST_ID et domain.

PriceClass_100 limite aux PoP Amérique/Europe (moins cher) — suffisant pour un lab. Attendez Status = Deployed (souvent 5–15+ min) :

aws cloudfront get-distribution --id "$DIST_ID" 
  --query 'Distribution.Status'

Sans bucket policy OAC, CloudFront peut se déployer mais renverra 403 à l’origine — normal jusqu’à l’étape 5.

Étape 5 — Bucket policy pour OAC

cat > /tmp/oac-bucket-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "AllowCloudFrontOAC",
    "Effect": "Allow",
    "Principal": { "Service": "cloudfront.amazonaws.com" },
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::${BUCKET}/*",
    "Condition": {
      "StringEquals": {
        "AWS:SourceArn": "arn:aws:cloudfront::${ACCOUNT_ID}:distribution/${DIST_ID}"
      }
    }
  }]
}
EOF

# BPA : BlockPublicPolicy peut rester true — cette policy n'est pas « publique »
aws s3api put-bucket-policy --bucket "$BUCKET" 
  --policy file:///tmp/oac-bucket-policy.json

La Condition AWS:SourceArn empêche toute autre distribution CloudFront (même dans votre compte) de lire le bucket. Oublier le DIST_ID correct est la cause n°1 des 403 lab.

Étape 6 — Tester HTTPS + invalidation

curl -sI "https://${DOMAIN}/" | head
curl -s "https://${DOMAIN}/" | head

Modifiez index.html, sync S3, puis invalidez (sinon cache TTL) :

aws s3 cp /tmp/cdn/index.html "s3://${BUCKET}/index.html" --region ca-central-1
aws cloudfront create-invalidation 
  --distribution-id "$DIST_ID" 
  --paths "/index.html" "/"

Alternative moins coûteuse en prod : versionner les assets (app.abc123.js) plutôt qu’invalider souvent. Les invalidations hors quota gratuit facturent par path ; un design « hash dans le nom » évite ce coût.

Cache behaviors utiles (aperçu SA)

  • Default (*) : HTML avec TTL court ou managed policy « CachingDisabled » pour index.html si mises à jour fréquentes.
  • /assets/* : TTL long + compress.
  • Viewer protocol : redirect-to-https (lab) ou https-only.

Les managed cache policies / origin request policies remplacent progressivement ForwardedValues dans les configs modernes — la console les propose par défaut. Pour l’examen : sachez que TTL viewer ≠ TTL origin, et qu’une invalidation force le refresh edge sans changer l’objet S3.

Étape 7 — Custom domain (aperçu, hors lab minimal)

  1. Certificat ACM us-east-1 (requis CloudFront — même si le bucket est en ca-central-1)
  2. Alternate domain names (CNAMEs) sur la distribution
  3. Alias Route 53 A/AAAA → distribution

On le mentionne pour la certif ; pas obligatoire pour valider OAC. Piège classique : demander le certificat ACM dans la Region du bucket → CloudFront le refuse.

Étape 8 — Vérification

Check Attendu
S3 objet URL directe AccessDenied
https://DOMAIN/ 200 + HTML
BPA all true
Policy Principal cloudfront.amazonaws.com + SourceArn distribution
Status Deployed
Origin domain bucket.s3.ca-central-1.amazonaws.com (REST, pas website)

Checklist : OAC créé · dist Deployed · policy SourceArn exact · HTTPS redirect · invalidation OK après sync.

Nettoyage

# Désactiver puis supprimer la distribution (2 étapes, attente)
# Console souvent plus simple : Disable → wait → Delete

aws s3api delete-bucket-policy --bucket "$BUCKET"
aws s3 rm "s3://$BUCKET" --recursive --region ca-central-1
aws s3api delete-bucket --bucket "$BUCKET"

# OAC : delete-origin-access-control après suppression dist

Contrôle anti-facture :

aws cloudfront list-distributions 
  --query "DistributionList.Items[?Comment=='lab-s3-oac'].{Id:Id,Status:Status,Enabled:Enabled}"
aws s3api list-buckets --query "Buckets[?contains(Name,'-cdn')].Name"

Ne laissez pas une distribution idle : elle a un coût de base faible mais réel hors Free Tier.

Erreurs fréquentes

Symptôme Cause probable Correction
403 via CloudFront Policy OAC / mauvais SourceArn DIST_ID + account dans Condition
403 après sync Cache Invalidation ou wait TTL
Origin domain wrong Endpoint website au lieu de REST bucket.s3.region.amazonaws.com
Create dist error Config JSON legacy OAI+OAC Console ou config OAC seule
ACM cert « invisible » Certificat hors us-east-1 Demander/importer en us-east-1
BPA bloque put-policy Confusion policy publique vs OAC OAC n’est pas publique ; BlockPublicPolicy OK
Dist reste InProgress Propagation normale Attendre Deployed (5–20 min)
curl S3 direct 200 Bucket encore public BPA + retirer policy publique

Lab bonus (5–8 min) — prouver le cache

  1. Notez l’en-tête X-Cache / Age sur curl -sI https://$DOMAIN/.
  2. Relancez immédiatement : vous devez voir un HIT (ou équivalent) si TTL > 0.
  3. Changez le <h1> dans index.html, sync sans invalidation : l’ancien contenu peut rester jusqu’au TTL.
  4. Créez l’invalidation /index.html : après completion, le nouveau HTML apparaît.

Ce mini-lab ancre : edge cache ≠ S3, et invalidation = outil volontaire (coût en prod).

Quiz (5 questions)

1. OAC sert surtout à :
– A. Remplacer Route 53
– B. Laisser CloudFront lire un bucket privé de façon signée
– C. Ouvrir S3 en public automatiquement

2. Le certificat ACM pour un nom custom CloudFront se demande en :
– A. La Region du bucket uniquement
– B. us-east-1
– C. eu-west-3 seulement

3. Après un changement de index.html sur S3, le navigateur peut voir l’ancienne page à cause :
– A. Du VPC
– B. Du cache CloudFront (TTL)
– C. Du versioning EBS

4. L’origin S3 recommandé avec OAC utilise :
– A. L’endpoint website s3-website-…
– B. L’endpoint REST bucket.s3.region.amazonaws.com
– C. Un Elastic IP

5. PriceClass_100 limite surtout :
– A. La taille des objets S3
– B. Les PoP (régions edge) utilisés — coût réduit
– C. Le nombre de buckets

Réponses : 1‑B · 2‑B · 3‑B · 4‑B · 5‑B

Pour aller plus loin

Maillage série AWS (P1)

← Précédent S3 versioning
→ Suivant VPC sous-réseaux & IGW
Aussi S3 site web (anti-pattern prod) · WAF · S3 sécurité

Retour parcours AWS — hub de la série et leçons sœurs.

Share your love

Leave a Reply

Your email address will not be published. Required fields are marked *