AWS code-library medium security documentation change
Summary
Enhanced script security with input validation, strict error handling, secure permissions, resource cleanup automation, and injection prevention
Security assessment
The changes implement multiple security best practices: 1) Added chmod 600 for log files and JSON dashboard files to prevent unauthorized access 2) Input validation for AWS region format to prevent command injection 3) JSON escaping for region/function names to prevent injection attacks 4) Automatic cleanup of temporary resources with rm -rf 5) Strict error handling with set -euo pipefail 6) Unique resource naming to prevent conflicts 7) JSON validation before CloudWatch submission. These address potential security vulnerabilities like insecure temporary files, command injection risks, and residual resource exposure.
Diff
diff --git a/code-library/latest/ug/lambda_example_cloudwatch_GettingStarted_031_section.md b/code-library/latest/ug/lambda_example_cloudwatch_GettingStarted_031_section.md index aa2e2fb25..eabbe9c02 100644 --- a//code-library/latest/ug/lambda_example_cloudwatch_GettingStarted_031_section.md +++ b//code-library/latest/ug/lambda_example_cloudwatch_GettingStarted_031_section.md @@ -40,2 +40,3 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Set up logging - LOG_FILE="cloudwatch-dashboard-script.log" + # Set up logging with secure permissions + LOG_FILE="${HOME}/.cloudwatch-dashboard-script.log" + touch "$LOG_FILE" && chmod 600 "$LOG_FILE" @@ -45,0 +47,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + # Security: Set strict error handling + set -euo pipefail + trap 'handle_error "Script failed at line $LINENO"' ERR + @@ -48 +53,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - echo "ERROR: $1" + local error_msg="${1:-Unknown error}" + echo "ERROR: $error_msg" >&2 @@ -55,2 +61 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - echo "An error occurred. Do you want to clean up the created resources? (y/n): " - read -r CLEANUP_CHOICE + echo "An error occurred. Proceeding with automatic cleanup..." @@ -58 +62,0 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - if [[ "${CLEANUP_CHOICE,,}" == "y" ]]; then @@ -60,4 +64,5 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - aws cloudwatch delete-dashboards --dashboard-names LambdaMetricsDashboard - echo "Cleanup complete." - else - echo "Resources were not cleaned up. You can manually delete them later." + aws cloudwatch delete-dashboards --dashboard-names LambdaMetricsDashboard 2>/dev/null || true + + # Clean up temporary files + if [ -n "${TEMP_DIR:-}" ] && [ -d "$TEMP_DIR" ]; then + rm -rf "$TEMP_DIR" @@ -64,0 +70,3 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + rm -f dashboard-body.json + + echo "Cleanup complete." @@ -67,0 +76,5 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + # Security: Validate AWS CLI is installed + if ! command -v aws &> /dev/null; then + handle_error "AWS CLI is not installed. Please install it and try again." + fi + @@ -70,2 +83 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - aws sts get-caller-identity > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if ! aws sts get-caller-identity > /dev/null 2>&1; then @@ -75,2 +87,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Get the current region - REGION=$(aws configure get region) + # Get the current region securely + REGION=$(aws configure get region 2>/dev/null || echo "") @@ -82,0 +95,5 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + # Validate region format + if ! [[ "$REGION" =~ ^[a-z]{2}-[a-z]+-[0-9]{1}$ ]]; then + handle_error "Invalid AWS region format: $REGION" + fi + @@ -85 +102,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - LAMBDA_FUNCTIONS=$(aws lambda list-functions --query "Functions[*].FunctionName" --output text) + LAMBDA_FUNCTIONS=$(aws lambda list-functions --region "$REGION" --query "Functions[*].FunctionName" --output text 2>/dev/null || echo "") + @@ -89 +107 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Create a temporary directory for Lambda function code + # Create a temporary directory for Lambda function code with secure permissions @@ -90,0 +109,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + chmod 700 "$TEMP_DIR" + trap 'rm -rf "$TEMP_DIR"' EXIT @@ -93 +113 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - cat > "$TEMP_DIR/index.js" << EOF + cat > "$TEMP_DIR/index.js" << 'EOF' @@ -104,2 +124,11 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - cd "$TEMP_DIR" || handle_error "Failed to change to temporary directory" - zip -q function.zip index.js + if ! cd "$TEMP_DIR"; then + handle_error "Failed to change to temporary directory" + fi + + if ! zip -q function.zip index.js; then + handle_error "Failed to create zip file" + fi + + # Create a role for the Lambda function with restricted trust policy + ROLE_NAME="LambdaDashboardTestRole-$(date +%s)" + TRUST_POLICY='{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"},"Action":"sts:AssumeRole"}]}' @@ -107,3 +136 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Create a role for the Lambda function - ROLE_NAME="LambdaDashboardTestRole" - ROLE_ARN=$(aws iam create-role \ + if ! ROLE_ARN=$(aws iam create-role \ @@ -111 +138 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"},"Action":"sts:AssumeRole"}]}' \ + --assume-role-policy-document "$TRUST_POLICY" \ @@ -113,3 +140 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - --output text) - - if [ $? -ne 0 ]; then + --output text 2>/dev/null); then @@ -123 +148 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - aws iam attach-role-policy \ + if ! aws iam attach-role-policy \ @@ -125,4 +150,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - - if [ $? -ne 0 ]; then - aws iam delete-role --role-name "$ROLE_NAME" + --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"; then + aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null || true @@ -133,2 +156,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - FUNCTION_NAME="DashboardTestFunction" - aws lambda create-function \ + FUNCTION_NAME="DashboardTestFunction-$(date +%s)" + if ! aws lambda create-function \ @@ -139,3 +162,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - --zip-file fileb://function.zip - - if [ $? -ne 0 ]; then + --zip-file fileb://function.zip \ + --region "$REGION" > /dev/null 2>&1; then @@ -144,2 +166,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - aws iam delete-role --role-name "$ROLE_NAME" + --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 2>/dev/null || true + aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null || true @@ -152 +174 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - aws lambda invoke --function-name "$FUNCTION_NAME" --payload '{}' /dev/null > /dev/null + aws lambda invoke --function-name "$FUNCTION_NAME" --payload '{}' /dev/null --region "$REGION" > /dev/null 2>&1 || true @@ -156 +178 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Clean up temporary directory + # Go back to original directory @@ -158 +179,0 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - rm -rf "$TEMP_DIR" @@ -165,0 +187,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + FUNCTION_NAME="" + ROLE_NAME="" @@ -171,2 +194,9 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Create a JSON file for the dashboard body - cat > dashboard-body.json << EOF + # Create a JSON file for the dashboard body with secure permissions + DASHBOARD_JSON="dashboard-body-$$.json" + touch "$DASHBOARD_JSON" && chmod 600 "$DASHBOARD_JSON" + + # Escape special characters in region and function name for JSON + REGION_ESCAPED=$(printf '%s\n' "$REGION" | sed 's:[\/&]:\\&:g') + FUNCTION_ESCAPED=$(printf '%s\n' "$DEFAULT_FUNCTION" | sed 's:[\/&]:\\&:g') + + cat > "$DASHBOARD_JSON" << EOF @@ -189 +219 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - "region": "$REGION", + "region": "$REGION_ESCAPED", @@ -206 +236 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - "region": "$REGION", + "region": "$REGION_ESCAPED", @@ -223 +253 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - "region": "$REGION", + "region": "$REGION_ESCAPED", @@ -239,2 +269,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - "value": "$DEFAULT_FUNCTION", - "label": "$DEFAULT_FUNCTION" + "value": "$FUNCTION_ESCAPED", + "label": "$FUNCTION_ESCAPED" @@ -248,3 +278,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Create the dashboard using the JSON file - DASHBOARD_RESULT=$(aws cloudwatch put-dashboard --dashboard-name LambdaMetricsDashboard --dashboard-body file://dashboard-body.json) - DASHBOARD_EXIT_CODE=$? + # Validate JSON before sending + if ! jq empty "$DASHBOARD_JSON" 2>/dev/null; then + handle_error "Invalid JSON generated for dashboard" + fi @@ -252,2 +283,5 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - # Check if there was a fatal error - if [ $DASHBOARD_EXIT_CODE -ne 0 ]; then + # Create the dashboard using the JSON file + if ! DASHBOARD_RESULT=$(aws cloudwatch put-dashboard \ + --dashboard-name "LambdaMetricsDashboard-$(date +%s)" \ + --dashboard-body file://"$DASHBOARD_JSON" \ + --region "$REGION" 2>&1); then @@ -256 +290 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - aws lambda delete-function --function-name "$FUNCTION_NAME" + aws lambda delete-function --function-name "$FUNCTION_NAME" --region "$REGION" 2>/dev/null || true @@ -259,2 +293,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - aws iam delete-role --role-name "$ROLE_NAME" + --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" 2>/dev/null || true + aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null || true @@ -266 +300 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - if [[ "$DASHBOARD_RESULT" == *"DashboardValidationMessages"* ]]; then + if echo "$DASHBOARD_RESULT" | grep -q "DashboardValidationMessages"; then @@ -273,0 +308,3 @@ There's more on GitHub. Find the complete example and learn how to set up and ru + # Extract dashboard name from result + DASHBOARD_NAME=$(echo "$DASHBOARD_RESULT" | grep -oP '"DashboardName"\s*:\s*"\K[^"]+' || echo "LambdaMetricsDashboard") + @@ -276,4 +313 @@ There's more on GitHub. Find the complete example and learn how to set up and ru - DASHBOARD_INFO=$(aws cloudwatch get-dashboard --dashboard-name LambdaMetricsDashboard) - DASHBOARD_INFO_EXIT_CODE=$? - - if [ $DASHBOARD_INFO_EXIT_CODE -ne 0 ]; then + if ! DASHBOARD_INFO=$(aws cloudwatch get-dashboard --dashboard-name "$DASHBOARD_NAME" --region "$REGION" 2>&1); then