### Access content through CloudFront Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/get-started-cli-tutorial.md Example URL to access content served by the CloudFront distribution. ```bash https://{{d111111abcdef8.cloudfront.net}}/index.html ``` -------------------------------- ### Install and package solution artifacts Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/getting-started-secure-static-website-cloudformation-template.md Command to install dependencies and package the solution's artifacts locally. ```bash make package-static ``` -------------------------------- ### Clean up local files Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/get-started-cli-tutorial.md Commands to remove local files created during the tutorial setup. ```bash # Clean up local files rm -f distribution-config.json bucket-policy.json temp_disabled_config.json rm -rf ~/cloudfront-demo ``` -------------------------------- ### Shell Script for CloudFront Setup Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/example_cloudfront_GettingStarted_section.md This script automates the process of creating an S3 bucket, uploading content, setting up Origin Access Control (OAC), and creating a CloudFront distribution. ```bash # Get AWS account ID early ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text) if [ $? -ne 0 ]; then handle_error "Failed to get AWS account ID" fi # Validate account ID format if ! [[ "$ACCOUNT_ID" =~ ^[0-9]{12}$ ]]; then handle_error "Invalid AWS account ID format: $ACCOUNT_ID" fi # Create a temporary directory for content with restrictive permissions TEMP_DIR="temp_content" mkdir -p "$TEMP_DIR/css" chmod 700 "$TEMP_DIR" if [ $? -ne 0 ]; then handle_error "Failed to create temporary directory" fi # Step 1: Create an S3 bucket (only if not shared) if [ "$BUCKET_IS_SHARED" != "true" ]; then echo "Creating S3 bucket: $BUCKET_NAME" aws s3 mb "s3://$BUCKET_NAME" --region us-east-1 if [ $? -ne 0 ]; then handle_error "Failed to create S3 bucket" fi aws s3api put-bucket-tagging --bucket "$BUCKET_NAME" --tagging 'TagSet=[{Key=project,Value=doc-smith},{Key=tutorial,Value=cloudfront-gettingstarted}]' # Batch bucket configuration calls for efficiency aws s3api put-bucket-versioning --bucket "$BUCKET_NAME" --versioning-configuration Status=Enabled & aws s3api put-public-access-block \ --bucket "$BUCKET_NAME" \ --public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true" & aws s3api put-bucket-encryption \ --bucket "$BUCKET_NAME" \ --server-side-encryption-configuration '{ \ "Rules": [ \ { \ "ApplyServerSideEncryptionByDefault": { \ "SSEAlgorithm": "AES256" \ } \ } \ ] \ }' & wait fi # Step 2: Create sample content echo "Creating sample content..." cat > "$TEMP_DIR/index.html" << 'EOF' Hello World

Hello world!

EOF cat > "$TEMP_DIR/css/styles.css" << 'EOF' body { font-family: Arial, sans-serif; margin: 40px; background-color: #f5f5f5; } h1 { color: #333; text-align: center; } EOF # Set restrictive permissions on content files chmod 600 "$TEMP_DIR/index.html" "$TEMP_DIR/css/styles.css" # Step 3: Upload content to the S3 bucket with encryption and metadata echo "Uploading content to S3 bucket..." aws s3 cp "$TEMP_DIR/" "s3://$BUCKET_NAME/" --recursive \ --sse AES256 \ --metadata "Source=CloudFrontTutorial" if [ $? -ne 0 ]; then handle_error "Failed to upload content to S3 bucket" fi # Step 4: Create Origin Access Control echo "Creating Origin Access Control..." OAC_RESPONSE=$(aws cloudfront create-origin-access-control \ --origin-access-control-config Name="oac-for-$BUCKET_NAME",SigningProtocol=sigv4,SigningBehavior=always,OriginAccessControlOriginType=s3) if [ $? -ne 0 ]; then handle_error "Failed to create Origin Access Control" fi OAC_ID=$(echo "$OAC_RESPONSE" | jq -r '.OriginAccessControl.Id') if [ -z "$OAC_ID" ] || [ "$OAC_ID" = "null" ]; then handle_error "Failed to extract OAC ID from response" fi # Validate OAC ID format (alphanumeric and hyphens) if ! [[ "$OAC_ID" =~ ^[A-Z0-9]+$ ]]; then handle_error "Invalid OAC ID format: $OAC_ID" fi echo "Created Origin Access Control with ID: $OAC_ID" # Step 5: Create CloudFront distribution echo "Creating CloudFront distribution..." # Validate bucket name format if ! [[ "$BUCKET_NAME" =~ ^[a-z0-9][a-z0-9.-]*[a-z0-9]$ ]]; then handle_error "Invalid S3 bucket name format: $BUCKET_NAME" fi # Create distribution configuration with improved security settings cat > distribution-config.json << EOF { "CallerReference": "cli-tutorial-$(date +%s)", "Origins": { "Quantity": 1, "Items": [ { "Id": "S3-$BUCKET_NAME", "DomainName": "$BUCKET_NAME.s3.amazonaws.com", "S3OriginConfig": { "OriginAccessIdentity": "" }, "OriginAccessControlId": "$OAC_ID" } ] }, "DefaultCacheBehavior": { "TargetOriginId": "S3-$BUCKET_NAME", "ViewerProtocolPolicy": "redirect-to-https", "AllowedMethods": { "Quantity": 2, "Items": ["GET", "HEAD"], "CachedMethods": { "Quantity": 2, "Items": ["GET", "HEAD"] } }, "DefaultTTL": 86400, "MinTTL": 0, "MaxTTL": 31536000, "Compress": true, "ForwardedValues": { "QueryString": false, "Cookies": { "Forward": "none" } } }, "Comment": "CloudFront distribution for tutorial", "Enabled": true, "WebACLId": "", "HttpVersion": "http2and3" } EOF ``` -------------------------------- ### Get method request example Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-custom-methods.md Example of how to use the get() method to fetch a key's value, specifying the format as a string. ```javascript const value = await kvsHandle.get("myFunctionKey", { format: "string"}); ``` -------------------------------- ### Download and extract sample content files Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/get-started-cli-tutorial.md These commands create a temporary directory, download sample "Hello World" webpage files, and extract them. ```bash # Create a temporary directory mkdir -p ~/cloudfront-demo # Download the sample Hello World files curl -o ~/cloudfront-demo/hello-world-html.zip https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/samples/hello-world-html.zip # Extract the zip file unzip ~/cloudfront-demo/hello-world-html.zip -d ~/cloudfront-demo/hello-world ``` -------------------------------- ### Upload the content to the bucket Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/get-started-cli-tutorial.md This command uploads the extracted "Hello World" files to your S3 bucket. Replace {{amzn-s3-demo-bucket}} with your bucket name. ```bash aws s3 cp ~/cloudfront-demo/hello-world/ s3://{{amzn-s3-demo-bucket}}/ --recursive ``` -------------------------------- ### Example: Creating a "dummy" origin Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/live-streaming.md This example demonstrates how to configure CloudFront origins and cache behaviors to handle MediaPackage endpoints, including a "dummy" origin for wildcard paths. ```text MediaPackage endpoints: https://3ae97e9482b0d011.mediapackage.us-west-2.amazonaws.com/out/v1/abc123/index.m3u8 https://3ae97e9482b0d011.mediapackage.us-west-2.amazonaws.com/out/v1/def456/index.m3u8 CloudFront Origin A: Domain: 3ae97e9482b0d011.mediapackage.us-west-2.amazonaws.com Path: None CloudFront Origin B: Domain: mediapackage.us-west-2.amazonaws.com Path: None CloudFront cache behavior: 1. Path: /out/v1/abc123/* forward to Origin A 2. Path: /out/v1/def456/* forward to Origin A 3. Path: * forward to Origin B ``` -------------------------------- ### Get method error handling example (sequential await) Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-custom-methods.md Example demonstrating sequential await for fetching multiple values to avoid high memory usage. ```javascript var value1 = await kvs.get('key1'); var value2 = await kvs.get('key2'); ``` -------------------------------- ### CloudFront Distribution Creation and Configuration Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/example_cloudfront_GettingStarted_section.md This script demonstrates how to create a CloudFront distribution, extract its ID and domain name, and tag it. It also includes error handling and validation steps. ```bash chmod 600 distribution-config.json DIST_RESPONSE=$(aws cloudfront create-distribution --distribution-config file://distribution-config.json) if [ $? -ne 0 ]; then handle_error "Failed to create CloudFront distribution" fi DISTRIBUTION_ID=$(echo "$DIST_RESPONSE" | jq -r '.Distribution.Id') DOMAIN_NAME=$(echo "$DIST_RESPONSE" | jq -r '.Distribution.DomainName') if [ -z "$DISTRIBUTION_ID" ] || [ "$DISTRIBUTION_ID" = "null" ] || [ -z "$DOMAIN_NAME" ] || [ "$DOMAIN_NAME" = "null" ]; then handle_error "Failed to extract distribution ID or domain name from response" fi # Validate distribution ID format if ! [[ "$DISTRIBUTION_ID" =~ ^[A-Z0-9]+$ ]]; then handle_error "Invalid distribution ID format: $DISTRIBUTION_ID" fi echo "Created CloudFront distribution with ID: $DISTRIBUTION_ID" echo "CloudFront domain name: $DOMAIN_NAME" # Tag the CloudFront distribution aws cloudfront tag-resource --resource "arn:aws:cloudfront::$ACCOUNT_ID:distribution/$DISTRIBUTION_ID" --tags 'Items=[{Key=project,Value=doc-smith},{Key=tutorial,Value=cloudfront-gettingstarted}]' ``` -------------------------------- ### Get method error handling example (Promise.all - not recommended) Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-custom-methods.md Example showing the use of Promise.all for fetching multiple values, which is not recommended due to potential high memory usage. ```javascript var values = await Promise.all([kvs.get('key1'), kvs.get('key2'),]); ``` -------------------------------- ### Invalidation paths examples Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/invalidation-specifying-objects.md Examples of how to specify paths for invalidation using wildcards. ```text /{{directory-path}}/* ``` ```text /{{directory-path}}/* ``` ```text /{{directory-path}}/{{file-name}}.* ``` ```text /{{directory-path}}/{{initial-characters-in-file-name}}* ``` ```text /{{directory-path}}/{{file-name}}.{{file-name-extension}}* ``` ```text /* ``` -------------------------------- ### Displaying Access Information Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/example_cloudfront_GettingStarted_section.md This section displays the final access information for the created CloudFront distribution, including the domain name and a summary of created resources. ```bash echo "CloudFront distribution is now deployed." # Step 8: Display access information echo "" echo "===== CloudFront Distribution Setup Complete =====" echo "You can access your content at: https://$DOMAIN_NAME/index.html" echo "" echo "Resources created:" echo "- S3 Bucket: $BUCKET_NAME" echo "- CloudFront Origin Access Control: $OAC_ID" echo "- CloudFront Distribution: $DISTRIBUTION_ID" echo "" echo "To clean up resources, run: cleanup" echo "" echo "Tutorial completed at $(date)" ``` -------------------------------- ### Example Log File Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/standard-logs-reference.md An example of a standard CloudFront log file, showing the header and a data row. ```log #Version: 1.0 #Fields: date time x-edge-location sc-bytes c-ip cs-method cs(Host) cs-uri-stem sc-status cs(Referer) cs(User-Agent) cs-uri-query cs(Cookie) x-edge-result-type x-edge-request-id x-host-header cs-protocol cs-bytes time-taken x-forwarded-for ssl-protocol ssl-cipher x-edge-response-result-type cs-protocol-version fle-status fle-encrypted-fields c-port time-to-first-byte x-edge-detailed-result-type sc-content-type sc-content-len sc-range-start sc-range-end 2019-12-04 21:02:31 LAX1 392 192.0.2.100 GET d111111abcdef8.cloudfront.net /index.html 200 - Mozilla/5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/78.0.3904.108%20Safari/537.36 - - Hit SOX4xwn4XV6Q4rgb7XiVGOHms_BGlTAC4KyHmureZmBNrjGdRLiNIQ== d111111abcdef8.cloudfront.net https 23 0.001 - TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 Hit HTTP/2.0 - - 11040 0.001 Hit text/html 78 - - ``` -------------------------------- ### AWS CLI with Bash script Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/example_wafv2_GettingStarted_052_section.md This script automates the creation of an AWS WAF Web ACL with a string match rule and AWS Managed Rules. It associates the Web ACL with a CloudFront distribution and includes steps for logging and resource cleanup. The script is designed for use with the AWS CLI and is available in a GitHub repository for a complete example. ```bash #!/bin/bash # AWS WAF Getting Started Script # This script creates a Web ACL with a string match rule and AWS Managed Rules, # associates it with a CloudFront distribution, and then cleans up all resources. set -euo pipefail # Security: Restrict file permissions umask 077 # Set up logging with secure file handling LOG_FILE="waf-tutorial.log" touch "$LOG_FILE" chmod 600 "$LOG_FILE" exec > >(tee -a "$LOG_FILE") 2>&1 echo "===================================================" echo "AWS WAF Getting Started Tutorial" echo "===================================================" echo "This script will create AWS WAF resources and associate" echo "them with a CloudFront distribution." echo "" # Maximum number of retries for operations MAX_RETRIES=3 # Function to handle errors securely handle_error() { local error_msg="$1" echo "ERROR: $error_msg" >&2 echo "Check the log file for details: $LOG_FILE" >&2 cleanup_resources exit 1 } # Function to validate AWS CLI JSON output validate_json() { local json_string="$1" if ! echo "$json_string" | jq empty 2>/dev/null; then return 1 fi return 0 } # Function to safely extract JSON values extract_json_value() { local json_string="$1" local key_path="$2" if ! validate_json "$json_string"; then return 1 fi echo "$json_string" | jq -r "$key_path" 2>/dev/null || return 1 } # Function to clean up resources securely cleanup_resources() { echo "" echo "===================================================" echo "CLEANING UP RESOURCES" echo "===================================================" if [ -n "${DISTRIBUTION_ID:-}" ] && [ -n "${WEB_ACL_ARN:-}" ]; then echo "Disassociating Web ACL from CloudFront distribution..." local account_id account_id=$(aws sts get-caller-identity --query Account --output text 2>/dev/null) || account_id="" if [ -z "$account_id" ]; then echo "Warning: Could not retrieve AWS account ID" return fi local disassociate_result disassociate_result=$(aws wafv2 disassociate-web-acl \ --resource-arn "arn:aws:cloudfront::${account_id}:distribution/${DISTRIBUTION_ID}" \ --region us-east-1 2>&1) || true if echo "$disassociate_result" | grep -qi "error"; then echo "Warning: Failed to disassociate Web ACL: $disassociate_result" else echo "Web ACL disassociated successfully." fi fi if [ -n "${WEB_ACL_ID:-}" ] && [ -n "${WEB_ACL_NAME:-}" ]; then echo "Deleting Web ACL..." local get_result get_result=$(aws wafv2 get-web-acl \ --name "$WEB_ACL_NAME" \ --scope CLOUDFRONT \ --id "$WEB_ACL_ID" \ --region us-east-1 2>&1) || true if echo "$get_result" | grep -qi "error"; then echo "Warning: Failed to get Web ACL for deletion: $get_result" echo "You may need to manually delete the Web ACL using the AWS Console." else local latest_token latest_token=$(extract_json_value "$get_result" '.WebACL.LockToken' 2>/dev/null) || latest_token="" if [ -n "$latest_token" ]; then local delete_result delete_result=$(aws wafv2 delete-web-acl \ --name "$WEB_ACL_NAME" \ --scope CLOUDFRONT \ --id "$WEB_ACL_ID" \ --lock-token "$latest_token" \ --region us-east-1 2>&1) || true if echo "$delete_result" | grep -qi "error"; then echo "Warning: Failed to delete Web ACL: $delete_result" echo "You may need to manually delete the Web ACL using the AWS Console." else echo "Web ACL deleted successfully." fi else echo "Warning: Could not extract lock token for deletion. You may need to manually delete the Web ACL." fi fi fi echo "Cleanup process completed." } # Security: Trap EXIT to ensure cleanup on any exit trap cleanup_resources EXIT ``` -------------------------------- ### Wait for distribution deployment Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/get-started-cli-tutorial.md This command waits until the CloudFront distribution has finished deploying. ```bash aws cloudfront wait distribution-deployed --id $DISTRIBUTION_ID ``` -------------------------------- ### Create a distribution configuration file Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/get-started-cli-tutorial.md This snippet shows how to create a JSON file named `distribution-config.json` with the necessary configuration for a CloudFront distribution. It includes placeholders for bucket names and Origin Access Control ID. ```bash cat > distribution-config.json << EOF { "CallerReference": "cli-example-$(date +%s)", "Origins": { "Quantity": 1, "Items": [ { "Id": "S3-{{amzn-s3-demo-bucket}}", "DomainName": "{{amzn-s3-demo-bucket}}.s3.amazonaws.com", "S3OriginConfig": { "OriginAccessIdentity": "" }, "OriginAccessControlId": "$OAC_ID" } ] }, "DefaultCacheBehavior": { "TargetOriginId": "S3-{{amzn-s3-demo-bucket}}", "ViewerProtocolPolicy": "redirect-to-https", "AllowedMethods": { "Quantity": 2, "Items": ["GET", "HEAD"], "CachedMethods": { "Quantity": 2, "Items": ["GET", "HEAD"] } }, "DefaultTTL": 86400, "MinTTL": 0, "MaxTTL": 31536000, "Compress": true, "ForwardedValues": { "QueryString": false, "Cookies": { "Forward": "none" } } }, "Comment": "CloudFront distribution for S3 bucket", "Enabled": true } EOF ``` -------------------------------- ### Java CloudFront Utilities Examples Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/example_cloudfront_CloudFrontUtilities_section.md Examples demonstrating how to get cookies for canned and custom policies using CloudFront utilities in Java. ```java CookiesForCannedPolicy cookiesForCannedPolicy = cloudFrontUtilities .getCookiesForCannedPolicy(cannedSignerRequest); logger.info("Cookie EXPIRES header [{}]", cookiesForCannedPolicy.expiresHeaderValue()); logger.info("Cookie KEYPAIR header [{}]", cookiesForCannedPolicy.keyPairIdHeaderValue()); logger.info("Cookie SIGNATURE header [{}]", cookiesForCannedPolicy.signatureHeaderValue()); return cookiesForCannedPolicy; } public static CookiesForCustomPolicy getCookiesForCustomPolicy(CustomSignerRequest customSignerRequest) { CookiesForCustomPolicy cookiesForCustomPolicy = cloudFrontUtilities .getCookiesForCustomPolicy(customSignerRequest); logger.info("Cookie POLICY header [{}]", cookiesForCustomPolicy.policyHeaderValue()); logger.info("Cookie KEYPAIR header [{}]", cookiesForCustomPolicy.keyPairIdHeaderValue()); logger.info("Cookie SIGNATURE header [{}]", cookiesForCustomPolicy.signatureHeaderValue()); return cookiesForCustomPolicy; } } ``` -------------------------------- ### Tenant Configuration Example Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/example_cloudfront_CreateDistribution_section.md An example of tenant configuration parameters for a CloudFront distribution. ```json { "TenantConfig": { "ParameterDefinitions": [ { "Name": "tenantName", "Definition": { "StringSchema": { "Comment": "tenantName parameter", "DefaultValue": "root", "Required": false } } } ] }, "ConnectionMode": "tenant-only" } } } ```