View a markdown version of this page

CloudFront exemples d'utilisation AWS CLI avec le script Bash - AWS Command Line Interface

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

CloudFront exemples d'utilisation AWS CLI avec le script Bash

Les exemples de code suivants vous montrent comment effectuer des actions et implémenter des scénarios courants à l'aide du script AWS Command Line Interface with Bash with CloudFront.

Les scénarios sont des exemples de code qui vous montrent comment accomplir des tâches spécifiques en appelant plusieurs fonctions au sein d’un même service ou combinés à d’autres Services AWS.

Chaque exemple inclut un lien vers le code source complet, où vous trouverez des instructions sur la configuration et l’exécution du code en contexte.

Rubriques

Scénarios

L’exemple de code suivant illustre comment :

  • Créer un compartiment Amazon S3

  • Importer du contenu dans le bucket

  • Création d'une CloudFront distribution avec OAC

  • nettoyer des ressources ;

AWS CLI avec le script Bash
Note

Il y en a plus à ce sujet GitHub. Trouvez l’exemple complet et découvrez comment le configurer et l’exécuter dans le référentiel d’exemples de code.

#!/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)"

L’exemple de code suivant illustre comment :

  • Création d'une liste ACL web

  • Ajouter une règle de correspondance de chaînes

  • Ajouter des règles gérées

  • Configurer la journalisation

  • nettoyer des ressources ;

AWS CLI avec le script Bash
Note

Il y en a plus à ce sujet GitHub. Trouvez l’exemple complet et découvrez comment le configurer et l’exécuter dans le référentiel d’exemples de code.

#!/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 # Generate a random identifier for resource names using secure method RANDOM_ID=$(openssl rand -hex 4) || handle_error "Failed to generate random ID" WEB_ACL_NAME="MyWebACL-${RANDOM_ID}" METRIC_NAME="MyWebACLMetrics-${RANDOM_ID}" echo "Using Web ACL name: $WEB_ACL_NAME" # Step 1: Create a Web ACL echo "" echo "===================================================" echo "STEP 1: Creating Web ACL" echo "===================================================" local create_result create_result=$(aws wafv2 create-web-acl \ --name "$WEB_ACL_NAME" \ --scope "CLOUDFRONT" \ --default-action Allow={} \ --visibility-config "SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=$METRIC_NAME" \ --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-waf-gs \ --region us-east-1 2>&1) || handle_error "Failed to create Web ACL" if ! validate_json "$create_result"; then handle_error "Invalid JSON response from create-web-acl" fi # Extract Web ACL ID, ARN, and Lock Token from the response WEB_ACL_ID=$(extract_json_value "$create_result" '.Summary.Id') || handle_error "Failed to extract Web ACL ID" WEB_ACL_ARN=$(extract_json_value "$create_result" '.Summary.ARN') || handle_error "Failed to extract Web ACL ARN" LOCK_TOKEN=$(extract_json_value "$create_result" '.Summary.LockToken') || handle_error "Failed to extract Lock Token" echo "Web ACL created successfully with ID: $WEB_ACL_ID" echo "Lock Token: [REDACTED]" # Step 2: Add a String Match Rule echo "" echo "===================================================" echo "STEP 2: Adding String Match Rule" echo "===================================================" for ((i=1; i<=MAX_RETRIES; i++)); do echo "Attempt $i to add string match rule..." # Get the latest lock token before updating 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 update: $get_result" if [ "$i" -eq "$MAX_RETRIES" ]; then handle_error "Failed to get Web ACL after $MAX_RETRIES attempts" fi sleep 2 continue fi if ! validate_json "$get_result"; then echo "Warning: Invalid JSON response from get-web-acl" if [ "$i" -eq "$MAX_RETRIES" ]; then handle_error "Invalid JSON response after $MAX_RETRIES attempts" fi sleep 2 continue fi local latest_token latest_token=$(extract_json_value "$get_result" '.WebACL.LockToken' 2>/dev/null) || true if [ -z "$latest_token" ]; then echo "Warning: Could not extract lock token for update" if [ "$i" -eq "$MAX_RETRIES" ]; then handle_error "Failed to extract lock token after $MAX_RETRIES attempts" fi sleep 2 continue fi local update_result update_result=$(aws wafv2 update-web-acl \ --name "$WEB_ACL_NAME" \ --scope "CLOUDFRONT" \ --id "$WEB_ACL_ID" \ --lock-token "$latest_token" \ --default-action Allow={} \ --rules '[{ "Name": "UserAgentRule", "Priority": 0, "Statement": { "ByteMatchStatement": { "SearchString": "MyAgent", "FieldToMatch": { "SingleHeader": { "Name": "user-agent" } }, "TextTransformations": [ { "Priority": 0, "Type": "NONE" } ], "PositionalConstraint": "EXACTLY" } }, "Action": { "Count": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "UserAgentRuleMetric" } }]' \ --visibility-config "SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=$METRIC_NAME" \ --region us-east-1 2>&1) || true if echo "$update_result" | grep -qi "WAFOptimisticLockException"; then echo "Optimistic lock exception encountered. Will retry with new lock token." if [ "$i" -eq "$MAX_RETRIES" ]; then handle_error "Failed to add string match rule after $MAX_RETRIES attempts" fi sleep 2 continue elif echo "$update_result" | grep -qi "error"; then handle_error "Failed to add string match rule: $update_result" else echo "String match rule added successfully." break fi done # Step 3: Add AWS Managed Rules echo "" echo "===================================================" echo "STEP 3: Adding AWS Managed Rules" echo "===================================================" for ((i=1; i<=MAX_RETRIES; i++)); do echo "Attempt $i to add AWS Managed Rules..." # Get the latest lock token before updating 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 update: $get_result" if [ "$i" -eq "$MAX_RETRIES" ]; then handle_error "Failed to get Web ACL after $MAX_RETRIES attempts" fi sleep 2 continue fi if ! validate_json "$get_result"; then echo "Warning: Invalid JSON response from get-web-acl" if [ "$i" -eq "$MAX_RETRIES" ]; then handle_error "Invalid JSON response after $MAX_RETRIES attempts" fi sleep 2 continue fi local latest_token latest_token=$(extract_json_value "$get_result" '.WebACL.LockToken' 2>/dev/null) || true if [ -z "$latest_token" ]; then echo "Warning: Could not extract lock token for update" if [ "$i" -eq "$MAX_RETRIES" ]; then handle_error "Failed to extract lock token after $MAX_RETRIES attempts" fi sleep 2 continue fi local update_result update_result=$(aws wafv2 update-web-acl \ --name "$WEB_ACL_NAME" \ --scope "CLOUDFRONT" \ --id "$WEB_ACL_ID" \ --lock-token "$latest_token" \ --default-action Allow={} \ --rules '[{ "Name": "UserAgentRule", "Priority": 0, "Statement": { "ByteMatchStatement": { "SearchString": "MyAgent", "FieldToMatch": { "SingleHeader": { "Name": "user-agent" } }, "TextTransformations": [ { "Priority": 0, "Type": "NONE" } ], "PositionalConstraint": "EXACTLY" } }, "Action": { "Count": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "UserAgentRuleMetric" } }, { "Name": "AWS-AWSManagedRulesCommonRuleSet", "Priority": 1, "Statement": { "ManagedRuleGroupStatement": { "VendorName": "AWS", "Name": "AWSManagedRulesCommonRuleSet", "ExcludedRules": [] } }, "OverrideAction": { "Count": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "AWS-AWSManagedRulesCommonRuleSet" } }]' \ --visibility-config "SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=$METRIC_NAME" \ --region us-east-1 2>&1) || true if echo "$update_result" | grep -qi "WAFOptimisticLockException"; then echo "Optimistic lock exception encountered. Will retry with new lock token." if [ "$i" -eq "$MAX_RETRIES" ]; then handle_error "Failed to add AWS Managed Rules after $MAX_RETRIES attempts" fi sleep 2 continue elif echo "$update_result" | grep -qi "error"; then handle_error "Failed to add AWS Managed Rules: $update_result" else echo "AWS Managed Rules added successfully." break fi done # Step 4: List CloudFront distributions echo "" echo "===================================================" echo "STEP 4: Listing CloudFront Distributions" echo "===================================================" local cf_result cf_result=$(aws cloudfront list-distributions --query "DistributionList.Items[*].{Id:Id,DomainName:DomainName}" --output table 2>&1) || cf_result="" if echo "$cf_result" | grep -qi "error"; then echo "Warning: Failed to list CloudFront distributions: $cf_result" echo "Continuing without CloudFront association." DISTRIBUTION_ID="" else echo "$cf_result" # Auto-select first CloudFront distribution if available echo "" echo "===================================================" echo "STEP 5: Associate Web ACL with CloudFront Distribution" echo "===================================================" local first_dist first_dist=$(aws cloudfront list-distributions --query "DistributionList.Items[0].Id" --output text 2>&1) || first_dist="" if [ -n "$first_dist" ] && [ "$first_dist" != "None" ] && ! echo "$first_dist" | grep -qi "error"; then DISTRIBUTION_ID="$first_dist" echo "Using CloudFront distribution: $DISTRIBUTION_ID" 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 for association" DISTRIBUTION_ID="" else local associate_result associate_result=$(aws wafv2 associate-web-acl \ --web-acl-arn "$WEB_ACL_ARN" \ --resource-arn "arn:aws:cloudfront::${account_id}:distribution/${DISTRIBUTION_ID}" \ --region us-east-1 2>&1) || true if echo "$associate_result" | grep -qi "error"; then echo "Warning: Failed to associate Web ACL with CloudFront distribution: $associate_result" echo "Continuing without CloudFront association." DISTRIBUTION_ID="" else echo "Web ACL associated with CloudFront distribution successfully." fi fi else echo "No CloudFront distributions available. Skipping association." DISTRIBUTION_ID="" fi fi # Display summary of created resources echo "" echo "===================================================" echo "RESOURCE SUMMARY" echo "===================================================" echo "Web ACL Name: $WEB_ACL_NAME" echo "Web ACL ID: $WEB_ACL_ID" echo "Web ACL ARN: $WEB_ACL_ARN" if [ -n "${DISTRIBUTION_ID:-}" ]; then echo "Associated CloudFront Distribution: $DISTRIBUTION_ID" fi echo "" # Auto-confirm cleanup echo "===================================================" echo "CLEANUP CONFIRMATION" echo "===================================================" echo "Proceeding with automatic cleanup of all created resources..." echo "" echo "===================================================" echo "Tutorial completed!" echo "===================================================" echo "Log file: $LOG_FILE"