AWS Security ChangesHomeSearch

AWS code-library documentation change

Service: code-library · 2026-05-01 · Documentation low

File: code-library/latest/ug/bash_2_emr_code_examples.md

Summary

Enhanced EMR example script with security best practices: added strict error handling, secure file permissions, S3 bucket encryption, public access blocking, credential validation, and cleanup improvements.

Security assessment

Changes implement security best practices but don't reference a specific vulnerability. Improvements include: error trapping and strict mode; S3 bucket encryption and public access blocking; permission hardening (chmod 600/400); credential validation; secure file cleanup; and safer variable handling. These are proactive measures.

Diff

diff --git a/code-library/latest/ug/bash_2_emr_code_examples.md b/code-library/latest/ug/bash_2_emr_code_examples.md
index 611f0df8c..740ab9721 100644
--- a//code-library/latest/ug/bash_2_emr_code_examples.md
+++ b//code-library/latest/ug/bash_2_emr_code_examples.md
@@ -51,0 +52 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    set -euo pipefail
@@ -53 +54,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Set up logging
+    # Security: Set strict mode and trap errors
+    trap 'handle_error "Script interrupted or command failed"' ERR
+    
+    # Set up logging with secure permissions
@@ -54,0 +59,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    touch "$LOG_FILE"
+    chmod 600 "$LOG_FILE"
@@ -64,2 +70,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        if [ -n "$BUCKET_NAME" ]; then echo "- S3 Bucket: $BUCKET_NAME"; fi
-        if [ -n "$CLUSTER_ID" ]; then echo "- EMR Cluster: $CLUSTER_ID"; fi
+        if [ -n "${BUCKET_NAME:-}" ]; then echo "- S3 Bucket: $BUCKET_NAME"; fi
+        if [ -n "${CLUSTER_ID:-}" ]; then echo "- EMR Cluster: $CLUSTER_ID"; fi
@@ -76 +82 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        echo "CLEANUP CONFIRMATION"
+        echo "CLEANUP IN PROGRESS"
@@ -78,4 +83,0 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        echo "Do you want to clean up all created resources? (y/n): "
-        read -r CLEANUP_CHOICE
-        
-        if [[ "${CLEANUP_CHOICE,,}" == "y" ]]; then
@@ -85 +87 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-            if [ -n "$CLUSTER_ID" ]; then
+        if [ -n "${CLUSTER_ID:-}" ]; then
@@ -87 +89 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-                aws emr terminate-clusters --cluster-ids "$CLUSTER_ID"
+            aws emr terminate-clusters --cluster-ids "$CLUSTER_ID" 2>/dev/null || true
@@ -90 +92 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-                aws emr wait cluster-terminated --cluster-id "$CLUSTER_ID"
+            aws emr wait cluster-terminated --cluster-id "$CLUSTER_ID" 2>/dev/null || true
@@ -94,2 +96,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-            # Delete S3 bucket and contents if it exists
-            if [ -n "$BUCKET_NAME" ]; then
+        # Delete S3 bucket and contents if it exists and is not shared
+        if [ -n "${BUCKET_NAME:-}" ] && [ "${BUCKET_IS_SHARED:-false}" != "true" ]; then
@@ -97 +99 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-                aws s3 rm "s3://$BUCKET_NAME" --recursive
+            aws s3 rm "s3://$BUCKET_NAME" --recursive 2>/dev/null || true
@@ -100 +102 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-                aws s3 rb "s3://$BUCKET_NAME"
+            aws s3 rb "s3://$BUCKET_NAME" 2>/dev/null || true
@@ -103,4 +105,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-            echo "Cleanup completed."
-        else
-            echo "Cleanup skipped. Resources will remain in your AWS account."
-            echo "To avoid ongoing charges, remember to manually delete these resources."
+        # Remove temporary key pair file if created by this script
+        if [ -f "${KEY_NAME_FILE:-}" ]; then
+            rm -f "$KEY_NAME_FILE"
+            echo "Removed temporary key pair file."
@@ -107,0 +110,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+        
+        echo "Cleanup completed."
@@ -109,0 +114,10 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    # Validate AWS CLI is installed and configured
+    if ! command -v aws &> /dev/null; then
+        handle_error "AWS CLI is not installed"
+    fi
+    
+    # Test AWS credentials
+    if ! aws sts get-caller-identity > /dev/null 2>&1; then
+        handle_error "AWS credentials are not configured or invalid"
+    fi
+    
@@ -114 +129,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --query 'Stacks[0].Outputs[?OutputKey==`BucketName`].OutputValue' --output text 2>/dev/null)
+        --query 'Stacks[0].Outputs[?OutputKey==`BucketName`].OutputValue' --output text 2>/dev/null || true)
+    
@@ -121 +137 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        BUCKET_NAME="emr${RANDOM_ID}"
+        BUCKET_NAME="emr-${RANDOM_ID}"
@@ -125 +141 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Create S3 bucket
+    # Create S3 bucket with security best practices
@@ -127,2 +143,21 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    aws s3 mb "s3://$BUCKET_NAME" || handle_error "Failed to create S3 bucket"
-    echo "S3 bucket created successfully."
+    aws s3 mb "s3://$BUCKET_NAME" --region "${AWS_REGION:-us-east-1}" || handle_error "Failed to create S3 bucket"
+    
+    # Enable bucket versioning for safety
+    aws s3api put-bucket-versioning --bucket "$BUCKET_NAME" --versioning-configuration Status=Enabled || true
+    
+    # Block public access to bucket
+    aws s3api put-public-access-block --bucket "$BUCKET_NAME" \
+        --public-access-block-configuration \
+        "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true" || true
+    
+    # Enable encryption on bucket
+    aws s3api put-bucket-encryption --bucket "$BUCKET_NAME" \
+        --server-side-encryption-configuration '{
+            "Rules": [{
+                "ApplyServerSideEncryptionByDefault": {
+                    "SSEAlgorithm": "AES256"
+                }
+            }]
+        }' || true
+    
+    echo "S3 bucket created successfully with security best practices."
@@ -173,0 +209,3 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    # Secure the script file
+    chmod 600 health_violations.py
+    
@@ -176 +214 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    aws s3 cp health_violations.py "s3://$BUCKET_NAME/" || handle_error "Failed to upload PySpark script"
+    aws s3 cp health_violations.py "s3://$BUCKET_NAME/" --sse AES256 || handle_error "Failed to upload PySpark script"
@@ -181 +219,7 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    curl -o food_establishment_data.zip https://docs.aws.amazon.com/emr/latest/ManagementGuide/samples/food_establishment_data.zip || handle_error "Failed to download sample data"
+    curl -sS -o food_establishment_data.zip "https://docs.aws.amazon.com/emr/latest/ManagementGuide/samples/food_establishment_data.zip" || handle_error "Failed to download sample data"
+    
+    # Verify downloaded file
+    if [ ! -f food_establishment_data.zip ] || [ ! -s food_establishment_data.zip ]; then
+        handle_error "Downloaded file is empty or missing"
+    fi
+    
@@ -184,0 +229,3 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    # Secure the sample data file
+    chmod 600 food_establishment_data.csv
+    
@@ -187 +234 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    aws s3 cp food_establishment_data.csv "s3://$BUCKET_NAME/" || handle_error "Failed to upload sample data"
+    aws s3 cp food_establishment_data.csv "s3://$BUCKET_NAME/" --sse AES256 || handle_error "Failed to upload sample data"
@@ -189,0 +237,3 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    # Clean up sensitive local files
+    rm -f food_establishment_data.zip health_violations.py
+    
@@ -192 +242 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    aws emr create-default-roles || handle_error "Failed to create default roles"
+    aws emr create-default-roles 2>/dev/null || true
@@ -197 +247 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    KEY_PAIRS=$(aws ec2 describe-key-pairs --query "KeyPairs[*].KeyName" --output text)
+    KEY_PAIRS=$(aws ec2 describe-key-pairs --query "KeyPairs[*].KeyName" --output text 2>/dev/null || true)
@@ -201,3 +251,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        KEY_NAME="emr-tutorial-key-$RANDOM_ID"
-        aws ec2 create-key-pair --key-name "$KEY_NAME" --query "KeyMaterial" --output text > "${KEY_NAME}.pem"
-        chmod 400 "${KEY_NAME}.pem"
+        KEY_NAME="emr-tutorial-key-${RANDOM_ID}"
+        KEY_NAME_FILE="${KEY_NAME}.pem"
+        aws ec2 create-key-pair --key-name "$KEY_NAME" --query "KeyMaterial" --output text > "$KEY_NAME_FILE"
+        chmod 400 "$KEY_NAME_FILE"
@@ -211 +262 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Launch EMR cluster
+    # Launch EMR cluster with security best practices
@@ -221 +272,3 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-      --log-uri "s3://$BUCKET_NAME/logs/")
+      --log-uri "s3://$BUCKET_NAME/logs/" \
+      --ebs-root-volume-size 100 \
+      --security-configuration "EMR-Tutorial-SecurityConfig" 2>/dev/null || true)
@@ -228,4 +281,9 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Extract cluster ID
-    CLUSTER_ID=$(echo "$CLUSTER_RESPONSE" | grep -o '"ClusterId": "[^"]*' | cut -d'"' -f4)
-    if [ -z "$CLUSTER_ID" ]; then
-        handle_error "Failed to extract cluster ID from response"
+    # Extract cluster ID using jq if available, otherwise use alternative parsing
+    if command -v jq &> /dev/null; then
+        CLUSTER_ID=$(echo "$CLUSTER_RESPONSE" | jq -r '.ClusterId // empty')
+    else
+        CLUSTER_ID=$(echo "$CLUSTER_RESPONSE" | grep -o '"ClusterId"[[:space:]]*:[[:space:]]*"[^"]*' | grep -o 'j-[A-Z0-9]*' || true)
+    fi
+    
+    if [ -z "$CLUSTER_ID" ] || [ "$CLUSTER_ID" == "null" ]; then
+        handle_error "Failed to extract cluster ID from response: $CLUSTER_RESPONSE"
@@ -243,0 +302,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+        WAIT_COUNT=0
+        MAX_WAIT=120
@@ -244,0 +305,3 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+            if [ $WAIT_COUNT -ge $MAX_WAIT ]; then
+                handle_error "Cluster did not reach WAITING state within timeout period"
+            fi
@@ -252,0 +316 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+            WAIT_COUNT=$((WAIT_COUNT + 1))
@@ -269,2 +333 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # FIXED: Check if jq is available before using it
-    # Extract step ID using the appropriate method based on available tools
+    # Extract step ID using appropriate method
@@ -272,3 +335 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        # Use jq if available
-        echo "Using jq to parse JSON response"
-        STEP_ID=$(echo "$STEP_RESPONSE" | jq -r '.StepIds[0]')
+        STEP_ID=$(echo "$STEP_RESPONSE" | jq -r '.StepIds[0] // empty')
@@ -276,15 +337 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        # Fallback to grep/awk if jq is not available
-        echo "jq not found, using grep for parsing"
-        STEP_ID=$(echo "$STEP_RESPONSE" | grep -o '"StepIds":\s*\[\s*"[^"]*"' | grep -o 's-[A-Z0-9]*')
-        if [ -z "$STEP_ID" ]; then
-            # Another fallback method
-            STEP_ID=$(echo "$STEP_RESPONSE" | grep -o '"StepIds":\s*\[\s*"[^"]*' | grep -o 's-[A-Z0-9]*')
-            if [ -z "$STEP_ID" ]; then
-                # One more attempt with a different pattern
-                STEP_ID=$(echo "$STEP_RESPONSE" | grep -o 's-[A-Z0-9]*')
-                if [ -z "$STEP_ID" ]; then
-                    echo "Full step response: $STEP_RESPONSE"
-                    handle_error "Failed to extract step ID from response"
-                fi