Skip to content

Commit 11d4873

Browse files
authored
Merge pull request #122 from aws-solutions-library-samples/feature/remove-route53-req
Make Amazon Route53 Optional and Add Amazon CloudFront Configuration Options
2 parents b3a86de + 84a022f commit 11d4873

File tree

16 files changed

+1087
-77
lines changed

16 files changed

+1087
-77
lines changed

.env.template

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,9 @@ LANGFUSE_SECRET_KEY=""
6262
LANGFUSE_HOST="" # Optional, defaults to https://cloud.langfuse.com
6363
FAKE_LLM_LOAD_TESTING_ENDPOINT_CERTIFICATE_ARN=""
6464
FAKE_LLM_LOAD_TESTING_ENDPOINT_HOSTED_ZONE_NAME=""
65-
FAKE_LLM_LOAD_TESTING_ENDPOINT_RECORD_NAME=""
65+
FAKE_LLM_LOAD_TESTING_ENDPOINT_RECORD_NAME=""
66+
67+
# CloudFront and Route53 Configuration
68+
USE_ROUTE53="false"
69+
USE_CLOUDFRONT="true"
70+
CLOUDFRONT_PRICE_CLASS="PriceClass_100"

README.md

Lines changed: 155 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Project ACTIVE as of Feb 15, 2025
77
- [Project Overview](#project-overview)
88
- [Architecture](#architecture)
99
- [AWS Services in this Guidance](#aws-services-in-this-Guidance)
10+
- [Distribution Options](#distribution-options)
1011
- [Cost](#cost)
1112
- [Cost Considerations](#cost-considerations)
1213
- [Cost Components](#cost-components)
@@ -27,7 +28,7 @@ If you are unfamiliar with LiteLLM, it provides a consistent interface to access
2728

2829
## Architecture
2930

30-
![Reference Architecture Diagram ECS EKS](./media/Reference_architecture_ECS_EKS_platform_combined.jpg)
31+
![Reference Architecture Diagram ECS EKS](./media/architecture.png)
3132

3233
### Architecture steps
3334

@@ -38,7 +39,154 @@ If you are unfamiliar with LiteLLM, it provides a consistent interface to access
3839
5. External model providers providers (OpenAI, Anthropic, Vertex AI etc.) are configured using LiteLLM Admin UI to enable additional LLM model access via unified application interface. Pre-existing configurations of third-party providers are integrated into the Gateway using LiteLLM APIs.
3940
6. LiteLLM integrates with [Amazon ElastiCache (Redis OSS)](https://aws.amazon.com/elasticache/), [Amazon Relational Database Service (RDS)](https://aws.amazon.com/rds/), and [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) services. Amazon ElastiCache enables multi-tenant distribution of application settings and prompt caching. Amazon RDS enables persistence of virtual API keys and other configuration settings provided by LiteLLM. AWS Secrets Manager stores external model provider credentials and other sensitive settings securely.
4041
7. LiteLLM and the API/middleware store application logs in the dedicated [Amazon S3](https://aws.amazon.com/s3) storage bucket for troubleshooting and access analysis.
41-
42+
43+
## Distribution Options
44+
45+
Starting with version 1.1.0, this solution supports flexible deployment scenarios to meet various security and accessibility requirements. You can customize how your LiteLLM gateway is accessed based on your specific needs.
46+
47+
### Deployment Scenarios
48+
49+
#### Scenario 1: Default - Public with CloudFront (Recommended)
50+
```bash
51+
USE_CLOUDFRONT="true"
52+
USE_ROUTE53="false"
53+
PUBLIC_LOAD_BALANCER="true"
54+
```
55+
56+
**Why choose this scenario:**
57+
- Global performance with low-latency access via CloudFront's edge locations
58+
- Enhanced security with AWS Shield Standard DDoS protection
59+
- Simplified HTTPS management with CloudFront's default certificate
60+
- Best option for public-facing AI services with global user base
61+
62+
**Security:**
63+
- CloudFront IP filtering restricts ALB access to only CloudFront traffic
64+
- WAF can be applied at the CloudFront level (requires global WAF)
65+
- Simpler certificate management using CloudFront's default certificate
66+
67+
**Access URL:** `https://d1234abcdef.cloudfront.net`
68+
69+
#### Scenario 2: Custom Domain with CloudFront
70+
```bash
71+
USE_CLOUDFRONT="true"
72+
USE_ROUTE53="true"
73+
PUBLIC_LOAD_BALANCER="true"
74+
HOSTED_ZONE_NAME="example.com"
75+
RECORD_NAME="genai"
76+
CERTIFICATE_ARN="arn:aws:acm:region:account:certificate/certificate-id"
77+
```
78+
79+
**Why choose this scenario:**
80+
- Brand consistency with your custom domain
81+
- Professional appearance and SEO benefits
82+
- Same global performance and security as Scenario 1
83+
84+
**Additional requirements:**
85+
- Route53 hosted zone for your domain
86+
- ACM certificate for your domain (must be in us-east-1 for CloudFront)
87+
88+
**Access URL:** `https://genai.example.com`
89+
90+
#### Scenario 3: Direct ALB Access (No CloudFront)
91+
```bash
92+
USE_CLOUDFRONT="false"
93+
USE_ROUTE53="true"
94+
PUBLIC_LOAD_BALANCER="true"
95+
HOSTED_ZONE_NAME="example.com"
96+
RECORD_NAME="genai"
97+
CERTIFICATE_ARN="arn:aws:acm:region:account:certificate/certificate-id"
98+
```
99+
100+
**Why choose this scenario:**
101+
- Lower latency for single-region deployments
102+
- Simplified architecture without CloudFront
103+
- Regional WAF can be directly applied to the ALB
104+
- Cost savings by eliminating CloudFront distribution
105+
106+
**Security considerations:**
107+
- No CloudFront layer means direct internet exposure of ALB
108+
- WAF protection becomes particularly important
109+
- ALB security group allows traffic from all IPs (0.0.0.0/0)
110+
111+
**Access URL:** `https://genai.example.com` (points directly to ALB)
112+
113+
#### Scenario 4: Private VPC Only
114+
```bash
115+
USE_CLOUDFRONT="false"
116+
USE_ROUTE53="true"
117+
PUBLIC_LOAD_BALANCER="false"
118+
HOSTED_ZONE_NAME="example.internal" # Often a private .internal domain
119+
RECORD_NAME="genai"
120+
CERTIFICATE_ARN="arn:aws:acm:region:account:certificate/certificate-id"
121+
```
122+
123+
**Why choose this scenario:**
124+
- Maximum security for internal enterprise applications
125+
- Complete isolation from public internet
126+
- Suitable for processing sensitive or proprietary data
127+
128+
**Access methods:**
129+
- VPN connection to the VPC
130+
- AWS Direct Connect
131+
- VPC peering with corporate network
132+
- Transit Gateway
133+
134+
**Security considerations:**
135+
- No public internet access possible
136+
- ALB security group only allows traffic from private subnet CIDRs
137+
- Requires network connectivity to the VPC for access
138+
139+
**Access URL:** `https://genai.example.internal` (resolves only within VPC or connected networks)
140+
141+
### Configuration Quick Reference
142+
143+
| Parameter | Default | Description |
144+
|-----------|---------|-------------|
145+
| `USE_CLOUDFRONT` | `true` | Enables CloudFront distribution for global delivery |
146+
| `USE_ROUTE53` | `false` | Enables Route53 for custom domain support |
147+
| `PUBLIC_LOAD_BALANCER` | `true` | Deploys ALB in public subnets |
148+
| `CLOUDFRONT_PRICE_CLASS` | `PriceClass_100` | CloudFront price class (100/200/All) |
149+
| `HOSTED_ZONE_NAME` | `""` | Route53 hosted zone name for custom domain |
150+
| `RECORD_NAME` | `""` | Record to create in Route53 (subdomain) |
151+
| `CERTIFICATE_ARN` | `""` | ARN of ACM certificate for custom domain |
152+
153+
### Security Considerations
154+
155+
Each deployment scenario offers different security characteristics:
156+
157+
1. **CloudFront with public ALB (Default)**:
158+
- ALB is in public subnets but protected by custom header authentication
159+
- Only traffic with the proper CloudFront secret header is allowed (except health check paths)
160+
- CloudFront provides an additional security layer with AWS Shield Standard DDoS protection
161+
- Best balance of accessibility and security for public services
162+
163+
2. **Direct ALB access (No CloudFront)**:
164+
- ALB directly accessible from internet
165+
- WAF protection is crucial for this deployment
166+
- Consider IP-based restrictions if possible
167+
168+
3. **Private VPC deployment**:
169+
- Highest security, no direct internet exposure
170+
- Requires VPN or Direct Connect for access
171+
- Consider for sensitive workloads or internal services
172+
173+
All scenarios maintain security best practices including:
174+
- HTTPS for all communications with TLS 1.2+
175+
- Security groups with principle of least privilege
176+
- WAF protection against common attacks
177+
- IAM roles with appropriate permissions
178+
179+
### CloudFront Authentication
180+
181+
When using CloudFront, a custom security mechanism is implemented:
182+
183+
1. CloudFront adds a secret header (`X-CloudFront-Secret`) to all requests sent to the ALB
184+
2. The ALB has listener rules that verify this header before allowing access
185+
3. Health check paths are specifically exempted to allow CloudFront origin health checks
186+
4. The secret is stable across deployments (won't change unless explicitly changed)
187+
188+
This provides a robust defense against direct ALB access even if someone discovers your ALB's domain name. The secret is only displayed once after creation in the Terraform outputs and is marked as sensitive.
189+
42190
### AWS Services in this Guidance
43191

44192
| **AWS Service** | **Role** | **Description** |
@@ -51,10 +199,11 @@ If you are unfamiliar with LiteLLM, it provides a consistent interface to access
51199
| [Amazon Web Applications Firewall](https://aws.amazon.com/waf/) (WAF) | Core Service | Protect guidance applications from common exploits |
52200
| [Amazon Elastic Container Registry](http://aws.amazon.com/ecr/) (ECR) | Supporting service | Stores and manages Docker container images for EKS deployments. |
53201
| [Elastic Load Balancer](https://aws.amazon.com/elasticloadbalancing/) (ALB) | Supporting service | Distributes incoming traffic across multiple targets in the EKS cluster. |
202+
| [Amazon CloudFront](https://aws.amazon.com/cloudfront/) | Supporting service | Global content delivery network for improved performance and security. |
54203
| [Amazon Simple Storage Service ](https://aws.amazon.com/s3) (S3) | Supporting service | Provides persistent object storage for Applications logs and other related data. |
55204
| [Amazon Relational Database Service ](https://aws.amazon.com/rds/) (RDS) | Supporting service | Enables persistence of virtual API keys and other configuration settings provided by LiteLLM. |
56205
| [Amazon ElastiCache Service (Redis OSS) ](https://aws.amazon.com/elasticache/) (OSS) | Supporting service | Enables multi-tenant distribution of application settings and prompt caching. |
57-
| [AWS Route 53](https://aws.amazon.com/route53/) | Supporting Service | Routes users to the guidance application via DNS records |
206+
| [AWS Route 53](https://aws.amazon.com/route53/) | Supporting Service | Optional DNS service for custom domain management |
58207
| [AWS Identity and Access Management](https://aws.amazon.com/iam/) (IAM) | Supporting service | Manages access to AWS services and resources securely, including ECS or EKS cluster access. |
59208
| [AWS Certificate Manager](https://aws.amazon.com/certificate-manager/) (ACM) | Security service | Manages SSL/TLS certificates for secure communication within the cluster. |
60209
| [Amazon CloudWatch](https://aws.amazon.com/cloudwatch/) | Monitoring service | Collects and tracks metrics, logs, and events from ECS, EKS and other AWS resources provisoned in the guidance |
@@ -118,8 +267,8 @@ While this implementation guide provides default configurations, customers are r
118267

119268
Customers should regularly review their AWS service usage patterns, adjust configurations as needed, and leverage AWS cost management tools to optimize their spending.
120269

121-
We recommend creating a [budget](https://docs.aws.amazon.com/cost-management/latest/userguide/budgets-create.html) 
122-
through [AWS Cost Explorer](http://aws.amazon.com/aws-cost-management/aws-cost-explorer/) to
270+
We recommend creating a [budget](https://docs.aws.amazon.com/cost-management/latest/userguide/budgets-create.html)
271+
through [AWS Cost Explorer](http://aws.amazon.com/aws-cost-management/aws-cost-explorer/) to
123272
help manage costs. Prices are subject to change and also depend on model provider usage patterns/volume of data. For full details, please refer to the pricing webpage for each AWS service used in this guidance.
124273

125274
### Sample Cost tables
@@ -268,6 +417,4 @@ For detailed information about the open source libraries used in this applicatio
268417

269418
## Notices
270419

271-
Customers are responsible for making their own independent assessment of the information in this Guidance. This Guidance: (a) is for informational purposes only, (b) represents AWS current product offerings and practices, which are subject to change without notice, and (c) does not create any commitments or assurances from AWS and its affiliates, suppliers or licensors. AWS products or services are provided “as is” without warranties, representations, or conditions of any kind, whether express or implied. AWS responsibilities and liabilities to its customers are controlled by AWS agreements, and this Guidance is not part of, nor does it modify, any agreement between AWS and its customers.
272-
273-
420+
Customers are responsible for making their own independent assessment of the information in this Guidance. This Guidance: (a) is for informational purposes only, (b) represents AWS current product offerings and practices, which are subject to change without notice, and (c) does not create any commitments or assurances from AWS and its affiliates, suppliers or licensors. AWS products or services are provided "as is" without warranties, representations, or conditions of any kind, whether express or implied. AWS responsibilities and liabilities to its customers are controlled by AWS agreements, and this Guidance is not part of, nor does it modify, any agreement between AWS and its customers.

deploy.sh

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ if [ ! -f ".env" ]; then
4646
cp .env.template .env
4747
fi
4848

49-
5049
SKIP_BUILD=false
5150
while [[ $# -gt 0 ]]; do
5251
case $1 in
@@ -66,10 +65,44 @@ APP_NAME=litellm
6665
MIDDLEWARE_APP_NAME=middleware
6766
LOG_BUCKET_STACK_NAME="log-bucket-stack"
6867
MAIN_STACK_NAME="litellm-stack"
69-
68+
TRACKING_STACK_NAME="tracking-stack"
7069
# Load environment variables from .env file
7170
source .env
7271

72+
# Auto-detect existing deployments and set defaults for backward compatibility
73+
if aws cloudformation describe-stacks --stack-name "${TRACKING_STACK_NAME}" &>/dev/null; then
74+
echo "Detected existing deployment - ensuring backward compatibility"
75+
# If variables aren't explicitly set in .env, use existing configuration
76+
if [ -z "$USE_ROUTE53" ]; then
77+
# For existing deployments where HOSTED_ZONE_NAME is set, maintain Route53 usage
78+
if [ -n "$HOSTED_ZONE_NAME" ] && [ -n "$RECORD_NAME" ]; then
79+
USE_ROUTE53="true"
80+
echo "→ Setting USE_ROUTE53=true to maintain existing configuration"
81+
else
82+
USE_ROUTE53="false"
83+
fi
84+
fi
85+
else
86+
echo "New deployment detected - using new defaults"
87+
# For new deployments, set defaults if not explicitly defined
88+
if [ -z "$USE_ROUTE53" ]; then
89+
USE_ROUTE53="false"
90+
echo "→ Setting USE_ROUTE53=false (default for new deployments)"
91+
fi
92+
fi
93+
94+
# Use CloudFront by default if not explicitly set
95+
if [ -z "$USE_CLOUDFRONT" ]; then
96+
USE_CLOUDFRONT="true"
97+
echo "→ Setting USE_CLOUDFRONT=true (default)"
98+
fi
99+
100+
# Set CloudFront price class if not defined
101+
if [ -z "$CLOUDFRONT_PRICE_CLASS" ]; then
102+
CLOUDFRONT_PRICE_CLASS="PriceClass_100"
103+
echo "→ Setting CLOUDFRONT_PRICE_CLASS=${CLOUDFRONT_PRICE_CLASS} (default)"
104+
fi
105+
73106
# Check if bucket exists
74107
if aws s3api head-bucket --bucket "$TERRAFORM_S3_BUCKET_NAME" 2>/dev/null; then
75108
echo "Terraform Bucket $TERRAFORM_S3_BUCKET_NAME already exists, skipping creation"
@@ -84,9 +117,21 @@ if [[ (-z "$LITELLM_VERSION") || ("$LITELLM_VERSION" == "placeholder") ]]; then
84117
exit 1
85118
fi
86119

87-
if [ -z "$CERTIFICATE_ARN" ] || [ -z "$RECORD_NAME" ]; then
88-
echo "Error: CERTIFICATE_ARN and RECORD_NAME must be set in .env file"
89-
exit 1
120+
# Update validation logic
121+
if [ "$USE_ROUTE53" = "true" ]; then
122+
if [ -z "$HOSTED_ZONE_NAME" ] || [ -z "$RECORD_NAME" ]; then
123+
echo "Error: When USE_ROUTE53=true, both HOSTED_ZONE_NAME and RECORD_NAME must be set in .env file"
124+
exit 1
125+
fi
126+
127+
if [ -z "$CERTIFICATE_ARN" ]; then
128+
echo "Warning: No CERTIFICATE_ARN provided. Using CloudFront-to-ALB HTTP communication with header authentication."
129+
echo "Note: Communication between users and CloudFront will still use HTTPS."
130+
fi
131+
else
132+
if [ -n "$HOSTED_ZONE_NAME" ] || [ -n "$RECORD_NAME" ]; then
133+
echo "Warning: HOSTED_ZONE_NAME and/or RECORD_NAME are set but will not be used because USE_ROUTE53=false"
134+
fi
90135
fi
91136

92137
echo "Certificate Arn: " $CERTIFICATE_ARN
@@ -325,6 +370,14 @@ export TF_VAR_disable_swagger_page=$DISABLE_SWAGGER_PAGE
325370
export TF_VAR_disable_admin_ui=$DISABLE_ADMIN_UI
326371
export TF_VAR_langfuse_public_key=$LANGFUSE_PUBLIC_KEY
327372
export TF_VAR_langfuse_secret_key=$LANGFUSE_SECRET_KEY
373+
export TF_VAR_use_route53=$USE_ROUTE53
374+
export TF_VAR_use_cloudfront=$USE_CLOUDFRONT
375+
export TF_VAR_cloudfront_price_class=$CLOUDFRONT_PRICE_CLASS
376+
377+
# Display CloudFront and Route53 configuration
378+
echo "USE_ROUTE53: $USE_ROUTE53"
379+
echo "USE_CLOUDFRONT: $USE_CLOUDFRONT"
380+
echo "CLOUDFRONT_PRICE_CLASS: $CLOUDFRONT_PRICE_CLASS"
328381

329382
if [ -n "${LANGFUSE_HOST}" ]; then
330383
export TF_VAR_langfuse_host=$LANGFUSE_HOST
@@ -355,7 +408,6 @@ if [ $? -eq 0 ]; then
355408
echo "Deployment successful. Extracting outputs..."
356409

357410
if [ "$DEPLOYMENT_PLATFORM" = "ECS" ]; then
358-
359411
LITELLM_ECS_CLUSTER=$(terraform output -raw LitellmEcsCluster)
360412
LITELLM_ECS_TASK=$(terraform output -raw LitellmEcsTask)
361413
SERVICE_URL=$(terraform output -raw ServiceURL)
@@ -378,6 +430,30 @@ if [ $? -eq 0 ]; then
378430
aws eks update-kubeconfig --region $aws_region --name $EKS_CLUSTER_NAME
379431
kubectl rollout restart deployment $EKS_DEPLOYMENT_NAME
380432
fi
433+
434+
# Validate CloudFront if enabled
435+
if [ "$USE_CLOUDFRONT" = "true" ]; then
436+
echo "Validating CloudFront deployment..."
437+
CF_DIST_ID=$(terraform output -raw cloudfront_distribution_id 2>/dev/null || echo "")
438+
if [ -n "$CF_DIST_ID" ]; then
439+
echo "✓ CloudFront distribution created successfully: $CF_DIST_ID"
440+
CF_DOMAIN=$(terraform output -raw cloudfront_domain_name 2>/dev/null || echo "")
441+
echo "✓ CloudFront domain: $CF_DOMAIN"
442+
echo "CloudFrontDomain=$CF_DOMAIN" >> resources.txt
443+
echo "CloudFrontID=$CF_DIST_ID" >> resources.txt
444+
445+
echo "Note: CloudFront distribution deployment may take 15-30 minutes to complete globally"
446+
else
447+
echo "⚠️ CloudFront distribution ID not found in outputs - this is expected if CloudFront module was not applied"
448+
fi
449+
fi
450+
451+
# Validate Route53 if used
452+
if [ "$USE_ROUTE53" = "true" ]; then
453+
echo "✓ Route53 configuration applied successfully"
454+
fi
455+
456+
echo "✓ Deployment completed successfully"
381457
else
382458
echo "Deployment failed"
383-
fi
459+
fi

litellm-terraform-stack/main.tf

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ resource "aws_cloudformation_stack" "guidance_deployment_metrics" {
66
template_body = <<STACK
77
{
88
"AWSTemplateFormatVersion": "2010-09-09",
9-
"Description": "Guidance for Running Generative AI Gateway Proxy on AWS. The Solution ID is SO9022 and the Solution Version is 1.0.0",
9+
"Description": "Guidance for Running Generative AI Gateway Proxy on AWS. The Solution ID is SO9022 and the Solution Version is 1.1.0",
1010
"Resources": {
1111
"EmptyResource": {
1212
"Type": "AWS::CloudFormation::WaitConditionHandle"
@@ -32,6 +32,7 @@ module "base" {
3232
rds_allocated_storage = var.rds_allocated_storage
3333
redis_node_type = var.redis_node_type
3434
redis_num_cache_clusters = var.redis_num_cache_clusters
35+
use_route53 = var.use_route53
3536
}
3637

3738
module "ecs_cluster" {
@@ -47,6 +48,9 @@ module "ecs_cluster" {
4748
ecr_middleware_repository_url = module.base.MiddlewareRepositoryUrl
4849
litellm_version = var.litellm_version
4950
config_bucket_name = module.base.ConfigBucketName
51+
use_route53 = var.use_route53
52+
use_cloudfront = var.use_cloudfront
53+
cloudfront_price_class = var.cloudfront_price_class
5054
openai_api_key = var.openai_api_key
5155
azure_openai_api_key = var.azure_openai_api_key
5256
azure_api_key = var.azure_api_key
@@ -195,4 +199,4 @@ module "eks_cluster" {
195199
langfuse_host = var.langfuse_host
196200

197201
depends_on = [ module.base ]
198-
}
202+
}

0 commit comments

Comments
 (0)