Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions python/apigw-http-api-lambda-dynamodb-python-cdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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,
),
)