Jeff’s Note #
“Unlike generic exam dumps, ADH analyzes this scenario through the lens of a Real-World Lead Developer.”
“For DVA-C02 candidates, the confusion often lies in understanding the separation between S3 as origin storage versus CloudFront as the caching layer. In production, this is about knowing exactly which API calls to include in your buildspec.yml to force cache refresh. This isn’t an architecture problem—it’s a deployment automation problem that every frontend team encounters. Let’s drill down.”
The Certification Drill (Simulated Question) #
Scenario #
A development team at StreamlineMedia Inc. maintains a marketing website using a serverless architecture. The site’s static assets (HTML, CSS, JavaScript, images) are stored in an S3 bucket and distributed globally through a CloudFront distribution. The company uses a custom domain (www.streamlinemedia.example) that maps to the CloudFront endpoint.
The team has implemented an automated deployment workflow using AWS CodePipeline. Whenever marketing content changes are committed to their CodeCommit repository, the pipeline triggers automatically. The workflow consists of:
- Source Stage: Pulls latest code from CodeCommit
- Build Stage: Invokes a CodeBuild project that executes commands defined in buildspec.yml
The buildspec.yml successfully:
- Compiles the static site
- Uploads all files to the S3 bucket using
aws s3 sync
The lead developer verifies that after each pipeline execution:
- ✅ New files appear correctly in the S3 bucket
- ✅ Accessing the S3 static website endpoint shows the updated content
- ❌ Accessing the site via the CloudFront custom domain still shows old content
The Requirement: #
Modify the buildspec.yml to ensure that CloudFront serves the updated content immediately after deployment, without requiring manual intervention.
The Options #
- A) Add additional S3 synchronization commands to properly align objects in the S3 bucket with new files from the source stage
- B) Include a command to delete all previous website files in the S3 bucket before redeploying new files
- C) Add an AWS CLI command to create a CloudFront cache invalidation for the updated files
- D) Configure cross-origin resource sharing (CORS) headers in the S3 bucket policy and redeploy the website files
Correct Answer #
Option C.
Quick Insight: The Developer’s Cache Lifecycle Imperative #
For DVA-C02, understanding CloudFront’s edge caching behavior is critical. S3 updates don’t automatically propagate to CloudFront edge locations. You must programmatically trigger invalidations using the AWS CLI command
aws cloudfront create-invalidationin your buildspec.yml. This is about API integration in automated workflows, not infrastructure design.
Content Locked: The Expert Analysis #
You’ve identified the answer. But do you know the implementation details that separate a Junior from a Senior?
The Expert’s Analysis #
Correct Answer #
Option C: Invalidate the file caches for the primary CloudFront distribution
The Winning Logic #
The core issue is CloudFront’s edge caching behavior. When you update files in S3 (the origin), CloudFront edge locations don’t automatically know about these changes. They continue serving cached versions until either:
- The TTL (Time To Live) expires, or
- You explicitly invalidate the cache
Developer-Specific Implementation:
In your buildspec.yml, add this to the post_build phase:
version: 0.2
phases:
build:
commands:
- echo "Building static site..."
- npm run build
post_build:
commands:
- echo "Deploying to S3..."
- aws s3 sync ./build s3://your-bucket-name --delete
- echo "Creating CloudFront invalidation..."
- aws cloudfront create-invalidation \
--distribution-id E1234EXAMPLE \
--paths "/*"
Key API Details for DVA-C02:
- API Call:
cloudfront:CreateInvalidation - Required IAM Permission: Your CodeBuild service role must have
cloudfront:CreateInvalidationandcloudfront:GetInvalidationpermissions - Path Patterns: Use
/*for all files or specific paths like/css/*for selective invalidation - Cost Consideration: First 1,000 invalidation paths per month are free; additional paths cost $0.005 each
- Invalidation Time: Typically completes within 10-15 minutes
Error Handling Pattern:
- |
INVALIDATION_ID=$(aws cloudfront create-invalidation \
--distribution-id $DISTRIBUTION_ID \
--paths "/*" \
--query 'Invalidation.Id' \
--output text)
echo "Invalidation ID: $INVALIDATION_ID"
# Optional: Wait for completion
aws cloudfront wait invalidation-completed \
--distribution-id $DISTRIBUTION_ID \
--id $INVALIDATION_ID
The Trap (Distractor Analysis) #
Why not Option A (Additional S3 synchronization)?
- The Misconception: Assuming the problem is with S3 object consistency
- Reality: The question explicitly states files are correctly visible in S3 and at the S3 website endpoint
- Technical Flaw:
aws s3 syncalready handles proper synchronization; running it multiple times doesn’t affect CloudFront edge caches - Exam Trap: Tests whether you understand the separation of concerns between storage (S3) and distribution (CloudFront)
Why not Option B (Delete and redeploy)?
- The Misconception: Thinking file replacement triggers CloudFront updates
- Reality: CloudFront caches based on object keys and ETags; even deleting and recreating doesn’t invalidate edge caches until TTL expiration
- Operational Risk: Causes downtime between deletion and redeployment
- Performance Impact: Inefficient for large sites; you’re re-uploading unchanged files unnecessarily
Why not Option D (Configure CORS)?
- The Misconception: Confusing CORS (Cross-Origin Resource Sharing) with cache control
- Reality: CORS headers control browser security policies for cross-domain requests, not CloudFront caching behavior
- When CORS Matters: Only relevant if your frontend JavaScript is making XHR/Fetch requests to the S3 bucket from a different domain
- Complete Red Herring: The scenario mentions accessing the website directly, not API calls from other origins
The Technical Blueprint #
buildspec.yml Complete Implementation:
version: 0.2
env:
variables:
S3_BUCKET: "streamlinemedia-website"
DISTRIBUTION_ID: "E2QWRTYUIOP123"
phases:
install:
runtime-versions:
nodejs: 18
commands:
- echo "Installing dependencies..."
- npm ci --production
pre_build:
commands:
- echo "Running tests..."
- npm test
build:
commands:
- echo "Building application..."
- npm run build
- echo "Build completed on $(date)"
post_build:
commands:
- echo "Syncing to S3..."
- aws s3 sync ./dist s3://${S3_BUCKET}/ \
--delete \
--cache-control "max-age=31536000,public" \
--exclude "*.html" \
--exclude "service-worker.js"
# HTML files with shorter cache
- aws s3 sync ./dist s3://${S3_BUCKET}/ \
--cache-control "max-age=300,public" \
--exclude "*" \
--include "*.html" \
--include "service-worker.js"
- echo "Creating CloudFront invalidation..."
- |
INVALIDATION_OUTPUT=$(aws cloudfront create-invalidation \
--distribution-id ${DISTRIBUTION_ID} \
--paths "/*" 2>&1)
if [ $? -eq 0 ]; then
INVALIDATION_ID=$(echo $INVALIDATION_OUTPUT | jq -r '.Invalidation.Id')
echo "✅ Invalidation created: ${INVALIDATION_ID}"
echo "Invalidation URL: https://console.aws.amazon.com/cloudfront/v3/home#/distributions/${DISTRIBUTION_ID}/invalidations/${INVALIDATION_ID}"
else
echo "❌ Invalidation failed: ${INVALIDATION_OUTPUT}"
exit 1
fi
artifacts:
files:
- '**/*'
base-directory: dist
cache:
paths:
- 'node_modules/**/*'
Required IAM Policy for CodeBuild Role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::streamlinemedia-website",
"arn:aws:s3:::streamlinemedia-website/*"
]
},
{
"Effect": "Allow",
"Action": [
"cloudfront:CreateInvalidation",
"cloudfront:GetInvalidation",
"cloudfront:ListInvalidations"
],
"Resource": "arn:aws:cloudfront::123456789012:distribution/E2QWRTYUIOP123"
}
]
}
The Comparative Analysis #
| Option | API Complexity | Performance Impact | Cost | Deployment Time | Use Case |
|---|---|---|---|---|---|
| C - CloudFront Invalidation ✅ | Low (single CLI call) | Minimal (targeted cache clear) | $0.005 per path after first 1,000/month | 10-15 min propagation | Standard practice for CI/CD deployments |
| A - Additional S3 Sync | Low | None (unnecessary operation) | No additional cost | No effect on CloudFront | Doesn’t address the actual problem |
| B - Delete & Redeploy | Medium (multiple operations) | High (downtime window) | Higher data transfer costs | Extended (causes outage) | Never recommended for production |
| D - CORS Configuration | Low | None (unrelated to caching) | No cost | No effect on cache | Only for cross-origin API requests |
Developer Decision Matrix:
| Scenario | Recommended Approach | Invalidation Pattern |
|---|---|---|
| Full site deployment | Option C with /* |
Invalidate all paths |
| Specific file updates | Option C with targeted paths | /images/logo.png, /css/main.css |
| High-frequency updates | Consider versioned filenames + Cache-Control headers | Minimize invalidations |
| Large-scale deployments | Versioned assets + HTML-only invalidation | /index.html, /*.html |
Real-World Application (Practitioner Insight) #
Exam Rule #
“For the DVA-C02 exam, when you see ‘S3 updates not reflected in CloudFront’, immediately think cache invalidation. The keyword combination of ‘CI/CD pipeline’ + ‘buildspec.yml’ + ‘CloudFront not showing updates’ = add aws cloudfront create-invalidation command.”
Real World #
“In production environments, we optimize this further:
-
Versioned Assets Strategy: Instead of invalidating everything, use content hashing in filenames (
main.a3f2b1c.js). Only invalidate HTML entry points:--paths "/index.html" "/about.html" -
CloudWatch Monitoring: Track invalidation status:
aws cloudfront get-invalidation \ --distribution-id $DIST_ID \ --id $INVALIDATION_ID \ --query 'Invalidation.Status' -
Blue/Green Deployments: For zero-downtime, some teams maintain two CloudFront distributions and swap DNS records instead of invalidating.
-
Lambda@Edge Alternative: For dynamic invalidation logic, use Lambda@Edge to modify cache behavior based on custom headers.
-
Cost Optimization: We batch deployments during low-traffic windows to use the free 1,000 invalidation paths quota efficiently.
Common Production Bug: Forgetting to grant cloudfront:CreateInvalidation permission to the CodeBuild role. The pipeline succeeds but invalidation silently fails. Always check CloudWatch Logs for the CodeBuild project.”
Stop Guessing, Start Mastering #
Disclaimer
This is a study note based on simulated scenarios for the AWS DVA-C02 exam. All company names, scenarios, and implementations are fictional and created for educational purposes. Always refer to official AWS documentation for production implementations.