⚠️ DISCLAIMER: This is sample code intended for demonstration only. Review and adapt security configurations before deploying to your environments.
This repository provides sample implementations for the patterns described in the AWS Blog Post: Zero-Downtime API Migration with User-Aware Traffic Splitting.
Note: This demo uses HTTP Basic Authentication for simplicity. In production environments, implement robust authentication using Amazon Cognito, OAuth 2.0, or AWS IAM authentication.
Strangler Fig Pattern: An architectural pattern for gradually migrating from legacy systems to modern implementations by incrementally routing traffic to new components while the old system continues running. Named after the strangler fig tree that grows around and eventually replaces its host tree.
User-Aware Routing: A traffic distribution strategy that ensures each user is consistently routed to the same API version throughout their session, preventing data inconsistencies.
- Zero-downtime migration with no service interruptions
- User-aware routing using deterministic hash-based assignment
- Gradual rollout with percentage-based traffic control
- Real-time adjustments without function redeployment
- Instant rollback capability for risk mitigation
The solution uses:
- Amazon CloudFront Distribution - AWS's content delivery network (CDN) that routes requests globally
- Amazon CloudFront Function - Lightweight JavaScript code that runs at edge locations to make routing decisions
- Amazon CloudFront Key Value Store - A low-latency data store that holds routing configuration and API endpoint URLs
- Amazon API Gateway - AWS's managed API service; we deploy multiple endpoints (A, B1, B2) representing old and new APIs
- AWS CDK - Infrastructure as Code toolkit that lets you define cloud resources using TypeScript
Phase 0 - Initial State: Legacy API (A) serves 100% of traffic Phase 1 - Establish the Fig: Deploy CDN layer and new APIs with 0% traffic routing Phase 2 - Gradual Strangulation: Incrementally shift traffic from 0% to 100% Phase 3 - Complete Migration: Route 100% traffic to new APIs, decommission legacy
The CloudFront function ensures users have a consistent experience by always sending the same user to the same API version:
- Extracts username from HTTP Authorization header
- Uses a hash function (a mathematical algorithm that converts the username into a consistent number)
- This number determines which API version the user should access
- The same username always produces the same number, ensuring consistent routing throughout the user's session
Before you begin, ensure you have the following tools installed:
- AWS CLI - Command-line tool for interacting with AWS services. Installation guide
- Configure with appropriate permissions for CloudFront, API Gateway, and IAM
- Node.js and npm - JavaScript runtime and package manager (version 18 or higher). Download
- AWS CDK CLI - Infrastructure as Code toolkit for defining cloud resources
- Install:
npm install -g aws-cdk - Getting started guide
- Install:
- jq - Command-line JSON processor for parsing deployment outputs. Installation guide
-
Install dependencies:
npm install
-
Deploy the CDK stack and save outputs:
cdk deploy --outputs-file outputs.json
-
Configure the Key Value Store with API endpoints:
./scripts/update-kvs.sh
-
Set traffic control percentage to route to legacy API:
./scripts/set-traffic-shift.sh 0 10
After deployment, test the CloudFront endpoint:
# Get the CloudFront domain from outputs.json
CLOUDFRONT_DOMAIN=$(cat outputs.json | jq -r '.DemoStack.CLOUDFRONTDOMAINNAME')
curl -L -H "Authorization:Basic $(echo -n test:test | base64)" https://$CLOUDFRONT_DOMAIN./scripts/send-test-requests.sh 5 # Send multiple requests in 5 seconds
./scripts/send-test-requests.sh 3600 # Send multiple requests in 1 hour# Start with 0% traffic to new APIs
./scripts/set-traffic-shift.sh 0 10
# Gradually increase to 25% over 60 seconds
./scripts/set-traffic-shift.sh 25 60
# Jump to 100% for complete migration over 60 seconds
./scripts/set-traffic-shift.sh 100 60
# Rollback to 0% if issues arise
./scripts/set-traffic-shift.sh 0 30- Traffic Control: Control the percentage of traffic being redirected to new APIs
- Dynamic Routing: Route traffic to specific APIs (B1, B2, etc.) based on URL patterns
- Low Latency: CloudFront Functions execute at edge locations for minimal latency
The CloudFront Key Value Store contains:
APIGW_A_URL: Original API Gateway endpointAPIGW_B1_URL: New API Gateway endpoint 1APIGW_B2_URL: New API Gateway endpoint 2traffic-split: Percentage of traffic to route to new APIs (0-100)
Why user-aware routing? To ensure a consistent experience, users should always be routed to the same API version throughout their session. This prevents mid-session switching that could cause data inconsistencies or confusing behavior.
The function uses a deterministic hash algorithm to consistently assign each user to either the legacy or new API based on their username. The same username always produces the same hash value, ensuring consistent routing:
String.prototype.hashCode = function() {
var hash = 0, i = 0, len = this.length;
while ( i < len ) {
hash = ((hash << 5) - hash + this.charCodeAt(i++)) << 0;
}
return hash + Math.pow(2,31);
};
function isShiftCandidate(username, trafficSplit){
return username.hashCode() % 100 < trafficSplit ? true : false;
}- Deploy the infrastructure using CDK
- Configure the Key Value Store with API endpoints
- Access the CloudFront URL to see traffic routing in action
- Requests are routed to different API Gateway endpoints based on configuration
- Each API returns a unique response:
{"message": "Hello from API 1"}or{"message": "Hello from API 2"}
If you need to manually manage the Key Value Store:
-
Get the Key Value Store ETAG:
aws cloudfront-keyvaluestore describe-key-value-store --kvs-arn=[KVS_ARN_FROM_OUTPUTS]
-
Update entries:
aws cloudfront-keyvaluestore update-keys \ --kvs-arn=[KVS_ARN_FROM_OUTPUTS] \ --if-match=[ETAG] \ --puts '[{"Key": "APIGW_A_URL", "Value": "[API_GATEWAY_1_URL]"}, {"Key": "APIGW_B1_URL", "Value": "[API_GATEWAY_2_URL]"}, {"Key": "APIGW_B2_URL", "Value": "[API_GATEWAY_3_URL]"}]'
├── bin/ # CDK app entry point
├── infra/ # CDK infrastructure code
├── scripts/ # Deployment and testing scripts
├── cdk.json # CDK configuration
├── package.json # Node.js dependencies
└── README.md # This file
npm run build- Compile TypeScript to JavaScriptnpm run watch- Watch for changes and compilenpx cdk deploy- Deploy the stack to your AWS account/regionnpx cdk diff- Compare deployed stack with current statenpx cdk synth- Emit the synthesized CloudFormation templatenpx cdk destroy- Remove the deployed stack
To remove all resources:
npx cdk destroyWhen adapting this solution for production use, consider the following:
- Authentication: Replace Basic Authentication with Amazon Cognito, OAuth 2.0, or IAM authentication
- WAF Integration: Enable AWS WAF on the CloudFront distribution and API Gateway endpoints for protection against common web exploits.
- Geo-Restrictions: Configure geographic restrictions if your application has regional compliance requirements
- API Gateway Authorization: Implement proper authorization on API Gateway endpoints
- Secrets Management: Use AWS Secrets Manager for any sensitive configuration
- Monitoring: Enable AWS CloudTrail and Amazon CloudWatch alarms for security monitoring
Further best practices can be found at AWS security best practices
1. Authentication Replace Basic Authentication with Amazon Cognito, OAuth 2.0, or IAM authentication
2. WAF Integration Enable AWS WAF on CloudFront distribution and API Gateway endpoints
3. API Gateway Authorization Implement proper authorization on API Gateway endpoints
5. Secrets Management Use AWS Secrets Manager for sensitive configuration
Use CloudFront KeyValueStore and Functions