Skip to content

Instantly share code, notes, and snippets.

@timmatheson
Created December 2, 2025 22:29
Show Gist options
  • Select an option

  • Save timmatheson/d40728b659b1ee4f130d2ff60ae99148 to your computer and use it in GitHub Desktop.

Select an option

Save timmatheson/d40728b659b1ee4f130d2ff60ae99148 to your computer and use it in GitHub Desktop.
AWS Optimized Load Balancer
AWSTemplateFormatVersion: '2010-09-09'
Description: Production-grade ALB for CAB Backend (HTTPS redirect, access logs, secure defaults)
Parameters:
Environment:
Type: String
AllowedPattern: ^(dev|staging|prod)$
Description: Environment name (dev/staging/prod)
VpcId:
Type: AWS::EC2::VPC::Id
Description: VPC for the ALB
PublicSubnetIds:
Type: List<AWS::EC2::Subnet::Id>
Description: At least two public subnets in different AZs
LoadBalancerSecurityGroupId:
Type: AWS::EC2::SecurityGroup::Id
Description: SG allowing 80/443 inbound to ALB
CertificateArn:
Type: String
Default: ""
Description: ACM certificate ARN (leave empty to disable HTTPS)
AccessLogsBucket:
Type: String
Default: ""
Description: S3 bucket for ALB access logs (e.g. cab-alb-logs-prod). Leave empty to disable.
EnableWaf:
Type: String
AllowedValues: ['true', 'false']
Default: 'false'
Description: Attach AWS Managed Rules WAF (recommended in prod)
Conditions:
HasCertificate: !Not [!Equals [!Ref CertificateArn, ""]]
EnableAccessLogs: !Not [!Equals [!Ref AccessLogsBucket, ""]]
AttachWaf: !Equals [!Ref EnableWaf, 'true']
Resources:
# Application Load Balancer
LoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub ${Environment}-cab
Type: application
Scheme: internet-facing
IpAddressType: ipv4
Subnets: !Ref PublicSubnetIds
SecurityGroups:
- !Ref LoadBalancerSecurityGroupId
LoadBalancerAttributes:
- Key: access_logs.s3.enabled
Value: !If [EnableAccessLogs, 'true', 'false']
- Key: access_logs.s3.bucket
Value: !If [EnableAccessLogs, !Ref AccessLogsBucket, !Ref "AWS::NoValue"]
- Key: access_logs.s3.prefix
Value: !If [EnableAccessLogs, !Sub alb/${Environment}, !Ref "AWS::NoValue"]
- Key: deletion_protection.enabled
Value: 'true'
- Key: routing.http2.enabled
Value: 'true'
- Key: routing.http.drop_invalid_header_fields.enabled
Value: 'true'
- Key: idle_timeout.timeout_seconds
Value: '350' # Critical for WebSocket/gRPC/Fargate
- Key: load_balancing.cross_zone.enabled
Value: 'true'
Tags:
- Key: Name
Value: !Sub ${Environment}-cab-alb
- Key: Environment
Value: !Ref Environment
- Key: Service
Value: cab-backend
# Target Group - IP targets (perfect for Fargate / ECS)
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${Environment}-cab
Port: 8080
Protocol: HTTP
ProtocolVersion: HTTP1 # Use HTTP/1.1 (better for streaming)
TargetType: ip
VpcId: !Ref VpcId
HealthCheckEnabled: true
HealthCheckPath: /health
HealthCheckProtocol: HTTP
HealthCheckPort: traffic-port
HealthCheckIntervalSeconds: 30
HealthCheckTimeoutSeconds: 10
HealthyThresholdCount: 3
UnhealthyThresholdCount: 3
Matcher:
HttpCode: 200-299 # Accept 201, etc.
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: '30'
# Removed sticky sessions - they hurt horizontal scaling
# If you really need them, add conditionally
Tags:
- Key: Name
Value: !Sub ${Environment}-cab-tg
- Key: Environment
Value: !Ref Environment
# HTTP → HTTPS Redirect Listener (always created)
HTTPListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref LoadBalancer
Port: 80
Protocol: HTTP
DefaultActions:
- Type: redirect
RedirectConfig:
Protocol: !If [HasCertificate, HTTPS, HTTP]
Port: !If [HasCertificate, '443', '80']
Host: '#{host}'
Path: '/#{path}'
Query: '#{query}'
StatusCode: HTTP_301
# HTTPS Listener (only if cert provided)
HTTPSListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Condition: HasCertificate
Properties:
LoadBalancerArn: !Ref LoadBalancer
Port: 443
Protocol: HTTPS
Certificates:
- CertificateArn: !Ref CertificateArn
SslPolicy: ELBSecurityPolicy-TLS13-1-3-2021-06 # Strongest available
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
# Optional: Attach WAFv2 (AWS Managed Rules)
WafAssociation:
Type: AWS::WAFv2::WebACLAssociation
Condition: AttachWaf
Properties:
ResourceArn: !Ref LoadBalancer
WebACLArn: !ImportValue AWSManagedRulesCommonRuleSet-WebACL # Or your own
Outputs:
LoadBalancerDnsName:
Description: ALB DNS name
Value: !GetAtt LoadBalancer.DNSName
Export:
Name: !Sub ${Environment}-cab-alb-dns
LoadBalancerCanonicalHostedZoneId:
Description: ALB canonical hosted zone ID (for Route53 alias)
Value: !GetAtt LoadBalancer.CanonicalHostedZoneID
LoadBalancerArn:
Description: ALB ARN
Value: !Ref LoadBalancer
TargetGroupArn:
Description: Target Group ARN (for ECS service)
Value: !Ref TargetGroup
Export:
Name: !Sub ${Environment}-cab-tg-arn
LoadBalancerUrl:
Description: Primary URL to access the service
Value: !If
- HasCertificate
- !Sub https://${LoadBalancer.DNSName}
- !Sub http://${LoadBalancer.DNSName}
LoadBalancerFullUrlWithPath:
Description: Example full URL
Value: !If
- HasCertificate
- !Sub https://${LoadBalancer.DNSName}/api/health
- !Sub http://${LoadBalancer.DNSName}/api/health
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment