diff --git a/python/apigw-http-api-lambda-dynamodb-python-cdk/README.md b/python/apigw-http-api-lambda-dynamodb-python-cdk/README.md index 6b74227f71..ead2f70847 100644 --- a/python/apigw-http-api-lambda-dynamodb-python-cdk/README.md +++ b/python/apigw-http-api-lambda-dynamodb-python-cdk/README.md @@ -6,8 +6,29 @@ Creates an [AWS Lambda](https://aws.amazon.com/lambda/) function writing to [Amazon DynamoDB](https://aws.amazon.com/dynamodb/) and invoked by [Amazon API Gateway](https://aws.amazon.com/api-gateway/) REST API. +This implementation follows AWS Well-Architected Framework best practices with comprehensive logging and monitoring capabilities. + ![architecture](docs/architecture.png) +## Security & Compliance Features + +This stack implements **SEC04-BP01: Configure service and application logging** from the AWS Well-Architected Framework: + +- **API Gateway Logging**: Access logs and execution logs with 1-year retention +- **Lambda Logging**: CloudWatch Logs with 1-year retention policy +- **VPC Flow Logs**: Network traffic monitoring with 1-month retention +- **DynamoDB PITR**: Point-in-time recovery enabled for data protection +- **CloudWatch Metrics**: API Gateway metrics enabled for monitoring + +### Log Retention Policies + +| Service | Log Type | Retention Period | +|---------|----------|------------------| +| API Gateway | Access Logs | 1 Year | +| API Gateway | Execution Logs | 1 Year | +| Lambda | Function Logs | 1 Year | +| VPC | Flow Logs | 1 Month | + ## Setup The `cdk.json` file tells the CDK Toolkit how to execute your app. @@ -85,6 +106,30 @@ You should get below response {"message": "Successfully inserted data!"} ``` +## Monitoring and Logs + +After deployment, you can access logs and metrics: + +### CloudWatch Logs +- **API Gateway Access Logs**: Navigate to CloudWatch Logs → Log group `/aws/apigateway/ApigwHttpApiLambdaDynamodbPythonCdkStack-ApiGatewayAccessLogs` +- **Lambda Function Logs**: Navigate to CloudWatch Logs → Log group `/aws/lambda/apigw_handler` +- **VPC Flow Logs**: Navigate to CloudWatch Logs → Log group for VPC Flow Logs + +### CloudWatch Insights Queries +Use CloudWatch Logs Insights to query logs: + +```sql +# API Gateway - Find errors +fields @timestamp, status, ip, requestId +| filter status >= 400 +| sort @timestamp desc + +# Lambda - Find slow requests +fields @timestamp, @duration +| filter @duration > 1000 +| sort @duration desc +``` + ## Cleanup Run below script to delete AWS resources created by this sample stack. ``` diff --git a/python/apigw-http-api-lambda-dynamodb-python-cdk/stacks/apigw_http_api_lambda_dynamodb_python_cdk_stack.py b/python/apigw-http-api-lambda-dynamodb-python-cdk/stacks/apigw_http_api_lambda_dynamodb_python_cdk_stack.py index 621034667e..9d8f053881 100644 --- a/python/apigw-http-api-lambda-dynamodb-python-cdk/stacks/apigw_http_api_lambda_dynamodb_python_cdk_stack.py +++ b/python/apigw-http-api-lambda-dynamodb-python-cdk/stacks/apigw_http_api_lambda_dynamodb_python_cdk_stack.py @@ -9,6 +9,7 @@ aws_apigateway as apigw_, aws_ec2 as ec2, aws_iam as iam, + aws_logs as logs, Duration, ) from constructs import Construct @@ -33,6 +34,21 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: ], ) + # Create log group for VPC Flow Logs + vpc_flow_log_group = logs.LogGroup( + self, + "VpcFlowLogs", + retention=logs.RetentionDays.ONE_MONTH, + ) + + # Enable VPC Flow Logs + ec2.FlowLog( + self, + "VpcFlowLog", + resource_type=ec2.FlowLogResourceType.from_vpc(vpc), + destination=ec2.FlowLogDestination.to_cloud_watch_logs(vpc_flow_log_group), + ) + # Create VPC endpoint dynamo_db_endpoint = ec2.GatewayVpcEndpoint( self, @@ -65,6 +81,7 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: partition_key=dynamodb_.Attribute( name="id", type=dynamodb_.AttributeType.STRING ), + point_in_time_recovery=True, ) # Create the Lambda function to receive the request @@ -81,15 +98,30 @@ def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: ), memory_size=1024, timeout=Duration.minutes(5), + log_retention=logs.RetentionDays.ONE_YEAR, ) # grant permission to lambda to write to demo table demo_table.grant_write_data(api_hanlder) api_hanlder.add_environment("TABLE_NAME", demo_table.table_name) - # Create API Gateway + # Create log group for API Gateway access logs + api_log_group = logs.LogGroup( + self, + "ApiGatewayAccessLogs", + retention=logs.RetentionDays.ONE_YEAR, + ) + + # Create API Gateway with logging enabled apigw_.LambdaRestApi( self, "Endpoint", handler=api_hanlder, + deploy_options=apigw_.StageOptions( + access_log_destination=apigw_.LogGroupLogDestination(api_log_group), + access_log_format=apigw_.AccessLogFormat.json_with_standard_fields(), + logging_level=apigw_.MethodLoggingLevel.INFO, + data_trace_enabled=True, + metrics_enabled=True, + ), )