View a markdown version of this page

開始使用基本 CloudFront 分佈 - Amazon CloudFront

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

開始使用基本 CloudFront 分佈

以下程式碼範例顯示做法:

  • 建立 Amazon S3 儲存貯體

  • 將內容上傳至儲存貯體

  • 使用 OAC 建立 CloudFront 分佈

  • 清除資源

Bash
AWS CLI 搭配 Bash 指令碼
注意

GitHub 上提供更多範例。尋找完整範例,並了解如何在範例開發人員教學課程儲存庫中設定和執行。

#!/bin/bash # CloudFront Getting Started Tutorial Script # This script creates an S3 bucket, uploads sample content, creates a CloudFront distribution with OAC, # and demonstrates how to access content through CloudFront. set -euo pipefail # Set up logging LOG_FILE="cloudfront-tutorial.log" exec > >(tee -a "$LOG_FILE") 2>&1 echo "Starting CloudFront Getting Started Tutorial at $(date)" # Function to handle errors handle_error() { echo "ERROR: $1" >&2 echo "Resources created before error:" if [ -n "${BUCKET_NAME:-}" ]; then echo "- S3 Bucket: $BUCKET_NAME" fi if [ -n "${OAC_ID:-}" ]; then echo "- CloudFront Origin Access Control: $OAC_ID" fi if [ -n "${DISTRIBUTION_ID:-}" ]; then echo "- CloudFront Distribution: $DISTRIBUTION_ID" fi echo "Attempting to clean up resources..." cleanup exit 1 } # Function to clean up resources cleanup() { echo "Cleaning up resources..." if [ -n "${DISTRIBUTION_ID:-}" ]; then echo "Disabling CloudFront distribution $DISTRIBUTION_ID..." # Get the current configuration and ETag in one call DIST_CONFIG=$(aws cloudfront get-distribution-config --id "$DISTRIBUTION_ID" 2>/dev/null) || { echo "Failed to get distribution config. Continuing with cleanup..." DIST_CONFIG="" } if [ -n "$DIST_CONFIG" ]; then ETAG=$(echo "$DIST_CONFIG" | jq -r '.ETag') # Modify and update distribution in one pipeline if echo "$DIST_CONFIG" | jq '.DistributionConfig.Enabled = false' | \ aws cloudfront update-distribution \ --id "$DISTRIBUTION_ID" \ --distribution-config "$(cat)" \ --if-match "$ETAG" 2>/dev/null; then echo "Waiting for distribution to be disabled (this may take several minutes)..." aws cloudfront wait distribution-deployed --id "$DISTRIBUTION_ID" 2>/dev/null || { echo "Distribution deployment wait timed out. Proceeding with deletion..." } # Get fresh ETag for deletion DIST_CONFIG=$(aws cloudfront get-distribution-config --id "$DISTRIBUTION_ID" 2>/dev/null) || { echo "Failed to get updated config. Skipping distribution deletion..." DIST_CONFIG="" } if [ -n "$DIST_CONFIG" ]; then ETAG=$(echo "$DIST_CONFIG" | jq -r '.ETag') aws cloudfront delete-distribution --id "$DISTRIBUTION_ID" --if-match "$ETAG" 2>/dev/null && \ echo "CloudFront distribution deleted." || \ echo "Failed to delete distribution. You may need to delete it manually." fi else echo "Failed to disable distribution. Continuing with cleanup..." fi fi fi if [ -n "${OAC_ID:-}" ]; then echo "Deleting Origin Access Control $OAC_ID..." OAC_DATA=$(aws cloudfront get-origin-access-control --id "$OAC_ID" 2>/dev/null) || { echo "Failed to get Origin Access Control. You may need to delete it manually." OAC_DATA="" } if [ -n "$OAC_DATA" ]; then OAC_ETAG=$(echo "$OAC_DATA" | jq -r '.ETag') aws cloudfront delete-origin-access-control --id "$OAC_ID" --if-match "$OAC_ETAG" 2>/dev/null && \ echo "Origin Access Control deleted." || \ echo "Failed to delete Origin Access Control. You may need to delete it manually." fi fi if [ -n "${BUCKET_NAME:-}" ] && [ "$BUCKET_IS_SHARED" != "true" ]; then echo "Deleting S3 bucket $BUCKET_NAME and its contents..." aws s3 rm "s3://$BUCKET_NAME" --recursive 2>/dev/null || { echo "Failed to remove bucket contents. Continuing with bucket deletion..." } aws s3 rb "s3://$BUCKET_NAME" 2>/dev/null && \ echo "S3 bucket deleted." || \ echo "Failed to delete bucket. You may need to delete it manually." fi # Clean up temporary files rm -f temp_disabled_config.json distribution-config.json bucket-policy.json 2>/dev/null || true rm -rf temp_content 2>/dev/null || true } # Trap errors and cleanup trap 'handle_error "Script interrupted"' INT TERM # Validate AWS CLI is available if ! command -v aws &> /dev/null; then handle_error "AWS CLI is not installed or not in PATH" fi # Validate jq is available if ! command -v jq &> /dev/null; then handle_error "jq is not installed or not in PATH" fi # Validate AWS credentials are configured if ! aws sts get-caller-identity &> /dev/null; then handle_error "AWS credentials are not configured or invalid" fi # Initialize variables BUCKET_NAME="" OAC_ID="" DISTRIBUTION_ID="" BUCKET_IS_SHARED=false # Generate a random identifier for the bucket name using secure random RANDOM_ID=$(openssl rand -hex 6) if [ -z "$RANDOM_ID" ]; then handle_error "Failed to generate random identifier" fi # Check for shared prereq bucket and get account ID in parallel calls PREREQ_BUCKET=$(aws cloudformation describe-stacks --stack-name tutorial-prereqs-bucket \ --query 'Stacks[0].Outputs[?OutputKey==`BucketName`].OutputValue' --output text 2>/dev/null) || PREREQ_BUCKET="" if [ -n "$PREREQ_BUCKET" ] && [ "$PREREQ_BUCKET" != "None" ]; then BUCKET_NAME="$PREREQ_BUCKET" BUCKET_IS_SHARED=true echo "Using shared bucket: $BUCKET_NAME" else BUCKET_IS_SHARED=false BUCKET_NAME="cloudfront-${RANDOM_ID}" fi echo "Using bucket name: $BUCKET_NAME" # 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' <!DOCTYPE html> <html> <head> <title>Hello World</title> <link rel="stylesheet" type="text/css" href="css/styles.css"> </head> <body> <h1>Hello world!</h1> </body> </html> 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 # Set restrictive permissions on config file before passing credentials 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}]' # Step 6: Update S3 bucket policy echo "Updating S3 bucket policy..." cat > bucket-policy.json << EOF { "Version":"2012-10-17", "Statement": [ { "Sid": "AllowCloudFrontServicePrincipal", "Effect": "Allow", "Principal": { "Service": "cloudfront.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::$BUCKET_NAME/*", "Condition": { "StringEquals": { "AWS:SourceArn": "arn:aws:cloudfront::$ACCOUNT_ID:distribution/$DISTRIBUTION_ID" } } } ] } EOF # Set restrictive permissions on policy file chmod 600 bucket-policy.json aws s3api put-bucket-policy --bucket "$BUCKET_NAME" --policy file://bucket-policy.json if [ $? -ne 0 ]; then handle_error "Failed to update S3 bucket policy" fi # Step 7: Wait for distribution to deploy echo "Waiting for CloudFront distribution to deploy (this may take 5-10 minutes)..." aws cloudfront wait distribution-deployed --id "$DISTRIBUTION_ID" 2>/dev/null || { echo "Warning: Distribution deployment wait timed out. The distribution may still be deploying." } 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)"

如需 AWS SDK 開發人員指南和程式碼範例的完整清單,請參閱 搭配 AWS SDK 使用 CloudFront。此主題也包含有關入門的資訊和舊版 SDK 的詳細資訊。