AWS Security ChangesHomeSearch

AWS IAM medium security documentation change

Service: IAM · 2026-05-01 · Security-related medium

File: IAM/latest/UserGuide/iam_example_api_gateway_GettingStarted_087_section.md

Summary

Updated API Gateway/Lambda tutorial with enhanced input validation, error handling, security hardening, and Python 3.11 runtime

Security assessment

Added input validation (ACCOUNT_ID/REGION checks), secure event data handling with type checks, input sanitization (quote escaping), proper error logging, exception handling to prevent information leakage, and explicit content-type headers. These changes mitigate injection risks and improve error handling security.

Diff

diff --git a/IAM/latest/UserGuide/iam_example_api_gateway_GettingStarted_087_section.md b/IAM/latest/UserGuide/iam_example_api_gateway_GettingStarted_087_section.md
index aeb952988..005d44056 100644
--- a//IAM/latest/UserGuide/iam_example_api_gateway_GettingStarted_087_section.md
+++ b//IAM/latest/UserGuide/iam_example_api_gateway_GettingStarted_087_section.md
@@ -38,0 +39,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    set -euo pipefail
+    
@@ -50,0 +53,6 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    # Validate inputs
+    if [[ -z "$ACCOUNT_ID" ]] || [[ -z "$REGION" ]]; then
+        echo "Error: Failed to retrieve AWS account information" >&2
+        exit 1
+    fi
+    
@@ -53 +61 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Create Lambda function code
+    # Create Lambda function code with input validation
@@ -55,0 +64 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    import logging
@@ -57,4 +66,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    def lambda_handler(event, context):
-        print(event)
-        
-        greeter = 'World'
+    logger = logging.getLogger()
+    logger.setLevel(logging.INFO)
@@ -61,0 +69 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    def lambda_handler(event, context):
@@ -63,5 +71 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-            if (event['queryStringParameters']) and (event['queryStringParameters']['greeter']) and (
-                    event['queryStringParameters']['greeter'] is not None):
-                greeter = event['queryStringParameters']['greeter']
-        except KeyError:
-            print('No greeter')
+            logger.info("Received event: %s", json.dumps(event))
@@ -69,6 +73 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        try:
-            if (event['multiValueHeaders']) and (event['multiValueHeaders']['greeter']) and (
-                    event['multiValueHeaders']['greeter'] is not None):
-                greeter = " and ".join(event['multiValueHeaders']['greeter'])
-        except KeyError:
-            print('No greeter')
+            greeter = 'World'
@@ -75,0 +75,24 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+            # Safely retrieve greeter from query string parameters
+            query_params = event.get('queryStringParameters') or {}
+            if isinstance(query_params, dict) and 'greeter' in query_params:
+                greeter_value = query_params.get('greeter')
+                if isinstance(greeter_value, str) and greeter_value:
+                    greeter = greeter_value
+            
+            # Safely retrieve greeter from multi-value headers
+            multi_headers = event.get('multiValueHeaders') or {}
+            if isinstance(multi_headers, dict) and 'greeter' in multi_headers:
+                greeter_list = multi_headers.get('greeter', [])
+                if isinstance(greeter_list, list) and greeter_list:
+                    greeter = " and ".join(str(g) for g in greeter_list if g)
+            
+            # Safely retrieve greeter from headers
+            headers = event.get('headers') or {}
+            if isinstance(headers, dict) and 'greeter' in headers:
+                greeter_value = headers.get('greeter')
+                if isinstance(greeter_value, str) and greeter_value:
+                    greeter = greeter_value
+            
+            # Safely retrieve greeter from body
+            body = event.get('body')
+            if body and isinstance(body, str):
@@ -77,15 +100,12 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-            if (event['headers']) and (event['headers']['greeter']) and (
-                    event['headers']['greeter'] is not None):
-                greeter = event['headers']['greeter']
-        except KeyError:
-            print('No greeter')
-        
-        if (event['body']) and (event['body'] is not None):
-            body = json.loads(event['body'])
-            try:
-                if (body['greeter']) and (body['greeter'] is not None):
-                    greeter = body['greeter']
-            except KeyError:
-                print('No greeter')
-        
-        res = {
+                    body_dict = json.loads(body)
+                    if isinstance(body_dict, dict) and 'greeter' in body_dict:
+                        greeter_value = body_dict.get('greeter')
+                        if isinstance(greeter_value, str) and greeter_value:
+                            greeter = greeter_value
+                except (json.JSONDecodeError, ValueError) as e:
+                    logger.warning("Failed to parse body: %s", str(e))
+            
+            # Sanitize greeter to prevent injection
+            greeter = greeter.replace('"', '\\"').replace("'", "\\'")
+            
+            response = {
@@ -94 +114 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-                "Content-Type": "*/*"
+                    "Content-Type": "application/json"
@@ -96 +116 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-            "body": "Hello, " + greeter + "!"
+                "body": json.dumps({"message": f"Hello, {greeter}!"})
@@ -99 +119,12 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        return res
+            logger.info("Response: %s", json.dumps(response))
+            return response
+            
+        except Exception as e:
+            logger.error("Unexpected error: %s", str(e), exc_info=True)
+            return {
+                "statusCode": 500,
+                "headers": {
+                    "Content-Type": "application/json"
+                },
+                "body": json.dumps({"error": "Internal server error"})
+            }
@@ -103 +134,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    zip function.zip lambda_function.py
+    zip -q function.zip lambda_function.py || {
+        echo "Error: Failed to create function.zip" >&2
+        exit 1
+    }
@@ -123 +157 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Create IAM role
+    # Create IAM role with error handling
@@ -126 +160,5 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --assume-role-policy-document file://trust-policy.json
+        --assume-role-policy-document file://trust-policy.json \
+        --description "Temporary role for Lambda execution" || {
+        echo "Error: Failed to create IAM role" >&2
+        exit 1
+    }
@@ -131 +169,4 @@ 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"
+        --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" || {
+        echo "Error: Failed to attach IAM policy" >&2
+        exit 1
+    }
@@ -138 +179 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Create Lambda function
+    # Create Lambda function with Python 3.11 (more recent runtime)
@@ -141 +182 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --runtime python3.9 \
+        --runtime python3.11 \
@@ -144 +185,7 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --zip-file fileb://function.zip
+        --zip-file fileb://function.zip \
+        --timeout 30 \
+        --memory-size 128 \
+        --environment "Variables={LOG_LEVEL=INFO}" || {
+        echo "Error: Failed to create Lambda function" >&2
+        exit 1
+    }
@@ -148,2 +195,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Create REST API
-    aws apigateway create-rest-api \
+    # Create REST API with minimum logging
+    API_RESPONSE=$(aws apigateway create-rest-api \
@@ -151 +198,3 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --endpoint-configuration types=REGIONAL
+        --endpoint-configuration types=REGIONAL \
+        --description "API for Lambda proxy integration tutorial" \
+        --output json)
@@ -153,2 +202,6 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Get API ID
-    API_ID=$(aws apigateway get-rest-apis --query "items[?name=='$API_NAME'].id" --output text)
+    API_ID=$(echo "$API_RESPONSE" | grep -o '"id": "[^"]*"' | head -1 | cut -d'"' -f4)
+    
+    if [[ -z "$API_ID" ]]; then
+        echo "Error: Failed to create API Gateway" >&2
+        exit 1
+    fi
@@ -163 +216,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --path-part helloworld
+        --path-part helloworld || {
+        echo "Error: Failed to create resource" >&2
+        exit 1
+    }
@@ -168 +224 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Create ANY method
+    # Create ANY method with no authorization (intentional for tutorial)
@@ -173 +229,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --authorization-type NONE
+        --authorization-type NONE || {
+        echo "Error: Failed to create method" >&2
+        exit 1
+    }
@@ -184 +243,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --uri "$LAMBDA_URI"
+        --uri "$LAMBDA_URI" || {
+        echo "Error: Failed to create integration" >&2
+        exit 1
+    }
@@ -186,0 +249 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    STATEMENT_ID="apigateway-invoke-$(openssl rand -hex 4)"
@@ -191 +254 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --statement-id "apigateway-invoke-$(openssl rand -hex 4)" \
+        --statement-id "$STATEMENT_ID" \
@@ -194 +257,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --source-arn "$SOURCE_ARN"