AWS CloudFormation CloudFront CDN
Overview
Create production-ready CDN infrastructure using AWS CloudFormation templates. This skill covers CloudFront distributions, multiple origins (ALB, S3, Lambda@Edge, VPC Origins), CacheBehaviors, Functions, SecurityHeaders, and best practices for parameters, outputs, and cross-stack references.
When to Use
Use this skill when:
- Creating new CloudFront distributions with CloudFormation
- Configuring multiple origins (ALB, S3, API Gateway, Lambda@Edge, VPC Origins)
- Implementing caching strategies with CacheBehaviors and Cache Policies
- Configuring custom domains with ACM certificates
- Implementing SecurityHeaders (CSP, HSTS, XSS protection)
- Configuring CloudFront Functions and Lambda@Edge
- Managing Geo-restrictions and Price Classes
- Integrating WAF with CloudFront
- Organizing templates with Parameters, Outputs, Mappings, Conditions
- Implementing cross-stack references with export/import
- Using Transform for macros and reuse
Instructions
Follow these steps to create CloudFront distributions with CloudFormation:
- Define Distribution Parameters: Specify domain names, ACM certificates, and price class
- Configure Origins: Add S3 buckets, ALBs, API Gateway, or custom origins
- Set Up Default Cache Behavior: Configure viewer request/response policies
- Add Additional Cache Behaviors: Create path-specific caching rules
- Configure Security Settings: Implement security headers and WAF integration
- Add Lambda@Edge Functions: Configure functions for request/response manipulation
- Set Up Custom Error Pages: Define error responses for specific HTTP status codes
- Create Monitoring: Configure logging and access logs to S3
For complete examples, see the EXAMPLES.md file.
Examples
The following examples demonstrate common CloudFront patterns:
Example 1: CloudFront Distribution with S3 Origin
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt S3Bucket.RegionalDomainName
Id: S3Origin
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${OAI}"
DefaultCacheBehavior:
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: !Ref CachePolicy
Enabled: true
HttpVersion: http2and3
IPV6Enabled: true
Example 2: Cache Policy Configuration
CachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
Name: !Sub "${AWS::StackName}-cache-policy"
DefaultTTL: 86400
MaxTTL: 31536000
MinTTL: 0
ParametersInCacheKeyAndForwardedToOrigin:
CookiesConfig:
CookieBehavior: none
HeadersConfig:
HeaderBehavior: none
QueryStringsConfig:
QueryStringBehavior: none
Example 3: Origin Request Policy
OriginRequestPolicy:
Type: AWS::CloudFront::OriginRequestPolicy
Properties:
OriginRequestPolicyConfig:
Name: !Sub "${AWS::StackName}-origin-request"
CookiesConfig:
CookieBehavior: all
HeadersConfig:
HeaderBehavior: whitelist
Headers:
- Origin
- Access-Control-Request-Method
- Access-Control-Request-Headers
QueryStringsConfig:
QueryStringBehavior: all
For complete production-ready examples, see EXAMPLES.md.
CloudFormation Template Structure
Standard Format Base Template
AWSTemplateFormatVersion: 2010-09-09
Description: CloudFront distribution with multiple origins
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Distribution Configuration
Parameters:
- DomainName
- CertificateArn
- PriceClass
- Label:
default: Origin Settings
Parameters:
- OriginDomainName
- OriginPath
- OriginProtocolPolicy
Parameters:
DomainName:
Type: String
Default: cdn.example.com
Description: Custom domain name for CloudFront distribution
CertificateArn:
Type: AWS::ACM::Certificate::Arn
Description: ACM certificate ARN for HTTPS
PriceClass:
Type: String
Default: PriceClass_All
AllowedValues:
- PriceClass_All
- PriceClass_100
- PriceClass_200
Description: CloudFront price class
OriginDomainName:
Type: String
Description: Domain name of the origin (ALB or S3)
OriginPath:
Type: String
Default: ""
Description: Optional origin path
Mappings:
EnvironmentConfig:
us-east-1:
CertificateRegion: us-east-1
other:
CertificateRegion: us-east-1
Conditions:
IsUsEast1: !Equals [!Ref AWS::Region, us-east-1]
HasOriginPath: !Not [!Equals [!Ref OriginPath, ""]]
Transform:
- AWS::Serverless-2016-10-31
Resources:
# CloudFront Distribution
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CallerReference: !Sub "${AWS::StackName}-${AWS::AccountId}"
Comment: !Sub "CloudFront distribution for ${DomainName}"
DomainNames:
- !Ref DomainName
Enabled: true
PriceClass: !Ref PriceClass
IPV6Enabled: true
DefaultRootObject: index.html
Origins:
- Id: !Sub "${DomainName}-origin"
DomainName: !Ref OriginDomainName
OriginPath: !If [HasOriginPath, !Ref OriginPath, !Ref AWS::NoValue]
CustomOriginConfig:
HTTPPort: 80
HTTPSPort: 443
OriginProtocolPolicy: https-only
OriginSSLProtocols:
- TLSv1.2
DefaultCacheBehavior:
TargetOriginId: !Sub "${DomainName}-origin"
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
Compress: true
ForwardedValues:
QueryString: false
Cookies:
Forward: none
MinTTL: 0
DefaultTTL: 86400
MaxTTL: 31536000
ViewerCertificate:
AcmCertificateArn: !Ref CertificateArn
MinimumProtocolVersion: TLSv1.2_2021
SslSupportMethod: sni-only
Outputs:
DistributionDomainName:
Description: CloudFront distribution domain name
Value: !GetAtt CloudFrontDistribution.DomainName
Export:
Name: !Sub "${AWS::StackName}-DistributionDomainName"
DistributionId:
Description: CloudFront distribution ID
Value: !Ref CloudFrontDistribution
Export:
Name: !Sub "${AWS::StackName}-DistributionId"
Best Practices for Parameters
AWS-Specific Parameter Types
Parameters:
# ACM Certificate for domain
CertificateArn:
Type: AWS::ACM::Certificate::Arn
Description: ACM certificate for the domain
# S3 Bucket origins
StaticAssetsBucket:
Type: AWS::S3::Bucket
Description: S3 bucket for static assets
StaticAssetsBucketDomainName:
Type: AWS::S3::Bucket::RegionalDomainName
Description: Regional domain name of the S3 bucket
# ALB origins
LoadBalancerArn:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer::Arn
Description: ARN of the Application Load Balancer
LoadBalancerDNSName:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer::DnsName
Description: DNS name of the ALB
# Lambda function origins
LambdaFunctionArn:
Type: AWS::Lambda::Function::Arn
Description: ARN of the Lambda function for Lambda@Edge
# VPC Origin
VPCOriginEndpoint:
Type: AWS::GlobalAccelerator::Endpoint::EndpointId
Description: VPC Origin endpoint ID
# IAM Role for Lambda@Edge
LambdaEdgeRoleArn:
Type: AWS::IAM::Role::Arn
Description: IAM role for Lambda@Edge execution
Parameter Constraints
Parameters:
DomainName:
Type: String
Default: cdn.example.com
Description: Custom domain name for CloudFront
ConstraintDescription: Must be a valid domain name
MinLength: 4
MaxLength: 253
AllowedPattern: "[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*"
PriceClass:
Type: String
Default: PriceClass_All
Description: CloudFront price class
AllowedValues:
- PriceClass_All
- PriceClass_100
- PriceClass_200
DefaultTTL:
Type: Number
Default: 86400
Description: Default cache TTL in seconds
MinValue: 0
MaxValue: 31536000
ConstraintDescription: Must be between 0 and 31536000 seconds
MaxTTL:
Type: Number
Default: 31536000
Description: Maximum cache TTL in seconds
MinValue: 0
MaxValue: 31536000
MinTTL:
Type: Number
Default: 0
Description: Minimum cache TTL in seconds
MinValue: 0
MaxValue: 31536000
SSM Parameter References
Parameters:
WafWebAclArn:
Type: AWS::SSM::Parameter::Value<String>
Default: /cloudfront/waf-webacl-arn
Description: WAF Web ACL ARN from Parameter Store
CloudFrontKeyId:
Type: AWS::SSM::Parameter::Value<String>
Default: /cloudfront/keys/cloudfront-key-id
Description: CloudFront key pair ID for signed URLs
Outputs and Cross-Stack References
Export/Import Patterns
# Stack A - Network/Infrastructure Stack
AWSTemplateFormatVersion: 2010-09-09
Description: Infrastructure stack exporting CloudFront resources
Resources:
# S3 Bucket for static content
StaticAssetsBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "static-assets-${AWS::AccountId}-${AWS::Region}"
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
VersioningConfiguration:
Status: Enabled
CorsConfiguration:
CorsRules:
- AllowedHeaders:
- "*"
AllowedMethods:
- GET
- HEAD
AllowedOrigins:
- "*"
MaxAge: 3600
# OAI for CloudFront access
CloudFrontOAI:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: !Sub "OAI for ${StaticAssetsBucket}"
Outputs:
StaticAssetsBucketName:
Description: S3 bucket name for static assets
Value: !Ref StaticAssetsBucket
Export:
Name: !Sub "${AWS::StackName}-StaticAssetsBucketName"
StaticAssetsBucketArn:
Description: S3 bucket ARN
Value: !GetAtt StaticAssetsBucket.Arn
Export:
Name: !Sub "${AWS::StackName}-StaticAssetsBucketArn"
StaticAssetsBucketRegionalDomainName:
Description: Regional domain name of the S3 bucket
Value: !GetAtt StaticAssetsBucket.RegionalDomainName
Export:
Name: !Sub "${AWS::StackName}-StaticAssetsBucketRegionalDomainName"
CloudFrontOAIId:
Description: CloudFront OAI ID
Value: !Ref CloudFrontOAI
Export:
Name: !Sub "${AWS::StackName}-CloudFrontOAIId"
CloudFrontOAIArn:
Description: CloudFront OAI ARN
Value: !GetAtt CloudFrontOAI.Arn
Export:
Name: !Sub "${AWS::StackName}-CloudFrontOAIArn"
# Stack B - Application Stack (imports from Infrastructure Stack)
AWSTemplateFormatVersion: 2010-09-09
Description: Application stack importing from infrastructure stack
Parameters:
InfrastructureStackName:
Type: String
Default: infrastructure-stack
Description: Name of the infrastructure stack
DomainName:
Type: String
Default: cdn.example.com
Description: Custom domain name
CertificateArn:
Type: AWS::ACM::Certificate::Arn
Description: ACM certificate ARN
Resources:
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CallerReference: !Sub "${AWS::StackName}-${AWS::AccountId}"
Comment: !Sub "CloudFront for ${DomainName}"
Enabled: true
IPV6Enabled: true
DefaultRootObject: index.html
Origins:
- Id: StaticAssetsOrigin
DomainName: !ImportValue
!Sub "${InfrastructureStackName}-StaticAssetsBucketRegionalDomainName"
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${InfrastructureStackName}-CloudFrontOAIId"
DefaultCacheBehavior:
TargetOriginId: StaticAssetsOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
Compress: true
ForwardedValues:
QueryString: false
Cookies:
Forward: none
MinTTL: 0
DefaultTTL: 86400
MaxTTL: 31536000
ViewerCertificate:
AcmCertificateArn: !Ref CertificateArn
MinimumProtocolVersion: TLSv1.2_2021
SslSupportMethod: sni-only
Nested Stacks for Modularity
AWSTemplateFormatVersion: 2010-09-09
Description: Main stack with nested CloudFront stacks
Resources:
# Nested stack for static assets distribution
StaticAssetsDistributionStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/bucket/cloudfront-static.yaml
TimeoutInMinutes: 15
Parameters:
DomainName: !Ref DomainName
CertificateArn: !Ref CertificateArn
StaticAssetsBucketName: !Ref StaticAssetsBucketName
Environment: !Ref Environment
# Nested stack for API distribution
ApiDistributionStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/bucket/cloudfront-api.yaml
TimeoutInMinutes: 15
Parameters:
DomainName: !Ref ApiDomainName
CertificateArn: !Ref CertificateArn
LoadBalancerDnsName: !Ref LoadBalancerDnsName
Environment: !Ref Environment
S3 Origins
S3 Origin with OAI
AWSTemplateFormatVersion: 2010-09-09
Description: CloudFront distribution with S3 origin
Resources:
# S3 Bucket
StaticBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "static-assets-${AWS::AccountId}-${AWS::Region}"
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
# CloudFront OAI
CloudFrontOAI:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: !Sub "OAI for ${StaticBucket}"
# S3 Bucket Policy - Allow CloudFront OAI
S3BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref StaticBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
CanonicalUser: !GetAtt CloudFrontOAI.S3CanonicalUserId
Action: s3:GetObject
Resource: !Sub "${StaticBucket.Arn}/*"
- Effect: Deny
Principal: "*"
Action: s3:GetObject
Resource: !Sub "${StaticBucket.Arn}/*"
Condition:
Bool:
aws:SecureTransport: false
# CloudFront Distribution
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CallerReference: !Sub "${AWS::StackName}-${AWS::AccountId}"
Comment: !Sub "Static assets CDN"
Enabled: true
IPV6Enabled: true
Origins:
- Id: S3Origin
DomainName: !GetAtt StaticBucket.RegionalDomainName
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOAI}"
DefaultCacheBehavior:
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
Compress: true
ForwardedValues:
QueryString: false
Cookies:
Forward: none
MinTTL: 0
DefaultTTL: 86400
MaxTTL: 31536000
Outputs:
DistributionDomainName:
Value: !GetAtt CloudFrontDistribution.DomainName
S3 Origin with Origin Access Control (OAC)
Resources:
StaticBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "static-assets-oac-${AWS::AccountId}-${AWS::Region}"
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerPreferred
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
# S3 Bucket Policy for OAC
S3BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref StaticBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action: s3:GetObject
Resource: !Sub "${StaticBucket.Arn}/*"
Condition:
StringEquals:
AWS:SourceArn: !Sub "arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}"
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: S3Origin
DomainName: !GetAtt StaticBucket.RegionalDomainName
S3OriginConfig:
OriginAccessIdentity: ""
# For OAC, use OriginAccessControl instead of S3OriginConfig
# but CloudFormation supports both
ALB Origins
Application Load Balancer Origin
AWSTemplateFormatVersion: 2010-09-09
Description: CloudFront with ALB origin
Resources:
# Application Load Balancer
ApplicationLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub "${AWS::StackName}-alb"
Scheme: internet-facing
SecurityGroups:
- !Ref ALBSecurityGroup
Subnets:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
Type: application
# ALB Security Group
ALBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ALB security group
VpcId: !Ref VPCId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref CloudFrontSecurityGroup
- IpProtocol: tcp
FromPort: 443
ToPort: 443
SourceSecurityGroupId: !Ref CloudFrontSecurityGroup
# CloudFront Security Group (for ALB ingress)
CloudFrontSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: CloudFront security group for ALB
VpcId: !Ref VPCId
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
DestinationSecurityGroupId: !Ref ALBSecurityGroup
- IpProtocol: tcp
FromPort: 443
ToPort: 443
DestinationSecurityGroupId: !Ref ALBSecurityGroup
# CloudFront Distribution
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CallerReference: !Sub "${AWS::StackName}-${AWS::AccountId}"
Comment: !Sub "CloudFront with ALB origin"
Enabled: true
Origins:
- Id: ALBOrigin
DomainName: !GetAtt ApplicationLoadBalancer.DNSName
CustomOriginConfig:
HTTPPort: 80
HTTPSPort: 443
OriginProtocolPolicy: https-only
OriginSSLProtocols:
- TLSv1.2
DefaultCacheBehavior:
TargetOriginId: ALBOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
- OPTIONS
CachedMethods:
- GET
- HEAD
Compress: true
ForwardedValues:
QueryString: true
Headers:
- Origin
- Access-Control-Request-Method
- Access-Control-Request-Headers
Cookies:
Forward: all
QueryStringSettings:
- Name: "*"
MinTTL: 0
DefaultTTL: 0
MaxTTL: 0
Multiple Origins and CacheBehaviors
Multi-Origin with Path Patterns
AWSTemplateFormatVersion: 2010-09-09
Description: CloudFront with multiple origins and cache behaviors
Resources:
# S3 Bucket for static assets
StaticAssetsBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "static-assets-${AWS::AccountId}-${AWS::Region}"
CloudFrontOAI:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: !Sub "OAI for ${StaticAssetsBucket}"
# Application Load Balancer for API
ApplicationLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub "${AWS::StackName}-api-alb"
Scheme: internet-facing
SecurityGroups:
- !Ref ALBSecurityGroup
Subnets: !Ref PublicSubnets
Type: application
# CloudFront Distribution
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CallerReference: !Sub "${AWS::StackName}-${AWS::AccountId}"
Comment: !Sub "Multi-origin CloudFront distribution"
Enabled: true
IPV6Enabled: true
DefaultRootObject: index.html
Origins:
# Static assets origin
- Id: StaticAssetsOrigin
DomainName: !GetAtt StaticAssetsBucket.RegionalDomainName
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOAI}"
# API origin
- Id: ApiOrigin
DomainName: !GetAtt ApplicationLoadBalancer.DNSName
CustomOriginConfig:
HTTPPort: 80
HTTPSPort: 443
OriginProtocolPolicy: https-only
# Lambda origin
- Id: LambdaOrigin
DomainName: !Sub "${LambdaFunction}.execute-api.${AWS::Region}.amazonaws.com"
CustomOriginConfig:
HTTPPort: 443
HTTPSPort: 443
OriginProtocolPolicy: https-only
DefaultCacheBehavior:
# Default: static assets
TargetOriginId: StaticAssetsOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
Compress: true
ForwardedValues:
QueryString: false
Cookies:
Forward: none
MinTTL: 0
DefaultTTL: 86400
MaxTTL: 31536000
CacheBehaviors:
# API cache behavior
- PathPattern: "/api/*"
TargetOriginId: ApiOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
- OPTIONS
- PUT
- POST
- PATCH
- DELETE
CachedMethods:
- GET
- HEAD
Compress: true
ForwardedValues:
QueryString: true
Headers:
- Accept
- Accept-Language
- Authorization
Cookies:
Forward: all
MinTTL: 0
DefaultTTL: 0
MaxTTL: 0
# Lambda function path
- PathPattern: "/lambda/*"
TargetOriginId: LambdaOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
- OPTIONS
CachedMethods:
- GET
- HEAD
Compress: true
ForwardedValues:
QueryString: true
Cookies:
Forward: none
MinTTL: 0
DefaultTTL: 0
MaxTTL: 0
Cache Policies
Managed Cache Policy
Resources:
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CacheBehaviors:
- PathPattern: "/static/*"
TargetOriginId: StaticAssetsOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
Compress: true
CachePolicyId: !Ref ManagedCachingOptimizedPolicyId
FunctionAssociations:
- FunctionARN: !GetAtt CloudFrontFunction.FunctionARN
EventType: viewer-request
- PathPattern: "/api/*"
TargetOriginId: ApiOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
- OPTIONS
CachedMethods:
- GET
- HEAD
Compress: true
CachePolicyId: !Ref ManagedSecurityHeadersPolicyId
Custom Cache Policy
Resources:
# Custom Cache Policy
StaticAssetsCachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
Name: !Sub "${AWS::StackName}-static-assets-policy"
DefaultTTL: 86400
MaxTTL: 31536000
MinTTL: 0
ParametersInCacheKeyAndForwardedToOrigin:
CookiesConfig:
CookieBehavior: none
HeadersConfig:
HeaderBehavior: none
QueryStringsConfig:
QueryStringBehavior: none
EnableAcceptEncodingBrotli: true
EnableAcceptEncodingGzip: true
# Custom Cache Policy for API
ApiCachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
Name: !Sub "${AWS::StackName}-api-cache-policy"
DefaultTTL: 300
MaxTTL: 600
MinTTL: 60
ParametersInCacheKeyAndForwardedToOrigin:
CookiesConfig:
CookieBehavior: all
HeadersConfig:
HeaderBehavior: whitelist
Headers:
- Authorization
- Content-Type
- Accept
QueryStringsConfig:
QueryStringBehavior: all
EnableAcceptEncodingBrotli: true
EnableAcceptEncodingGzip: true
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: StaticAssetsOrigin
DomainName: !GetAtt StaticAssetsBucket.RegionalDomainName
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOAI}"
CacheBehaviors:
- PathPattern: "/static/*"
TargetOriginId: StaticAssetsOrigin
CachePolicyId: !GetAtt StaticAssetsCachePolicy.Id
Origin Request Policies
Resources:
# Origin Request Policy
StaticAssetsOriginRequestPolicy:
Type: AWS::CloudFront::OriginRequestPolicy
Properties:
OriginRequestPolicyConfig:
Name: !Sub "${AWS::StackName}-static-assets-origin-request"
CookiesConfig:
CookieBehavior: none
HeadersConfig:
HeaderBehavior: none
QueryStringsConfig:
QueryStringBehavior: none
ApiOriginRequestPolicy:
Type: AWS::CloudFront::OriginRequestPolicy
Properties:
OriginRequestPolicyConfig:
Name: !Sub "${AWS::StackName}-api-origin-request"
CookiesConfig:
CookieBehavior: all
HeadersConfig:
HeaderBehavior: whitelist
Headers:
- Authorization
- Content-Type
- X-Request-ID
QueryStringsConfig:
QueryStringBehavior: all
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CacheBehaviors:
- PathPattern: "/api/*"
TargetOriginId: ApiOrigin
CachePolicyId: !GetAtt ApiCachePolicy.Id
OriginRequestPolicyId: !GetAtt ApiOriginRequestPolicy.Id
Response Headers Policies (Security Headers)
Resources:
# Security Headers Policy
SecurityHeadersPolicy:
Type: AWS::CloudFront::ResponseHeadersPolicy
Properties:
ResponseHeadersPolicyConfig:
Name: !Sub "${AWS::StackName}-security-headers"
SecurityHeadersConfig:
ContentTypeOptions:
Override: true
FrameOptions:
FrameOption: DENY
Override: true
ReferrerPolicy:
ReferrerPolicy: strict-origin-when-cross-origin
Override: true
StrictTransportSecurity:
AccessControlMaxAgeSec: 31536000
IncludeSubdomains: true
Override: true
Preload: true
XSSProtection:
ModeBlock: true
Override: true
Protection: true
CorsConfig:
AccessControlAllowCredentials: false
AccessControlAllowHeaders:
Items:
- "*"
AccessControlAllowMethods:
Items:
- GET
- HEAD
- OPTIONS
AccessControlAllowOrigins:
Items:
- !Ref AllowedOrigin
AccessControlMaxAgeSec: 600
OriginOverride: true
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
DefaultCacheBehavior:
TargetOriginId: StaticAssetsOrigin
ResponseHeadersPolicyId: !GetAtt SecurityHeadersPolicy.Id
CloudFront Functions
Viewer Request Function
Resources:
# CloudFront Function
RewritePathFunction:
Type: AWS::CloudFront::Function
Properties:
Name: !Sub "${AWS::StackName}-rewrite-path"
FunctionCode: |
function handler(event) {
var request = event.request;
var uri = request.uri;
// Remove trailing slash
if (uri.endsWith('/')) {
request.uri = uri.substring(0, uri.length - 1);
}
// Add .html extension for HTML pages
if (!uri.includes('.') && !uri.endsWith('/')) {
request.uri = uri + '.html';
}
return request;
}
Runtime: cloudfront-js-1.0
AutoPublish: true
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
DefaultCacheBehavior:
TargetOriginId: StaticAssetsOrigin
FunctionAssociations:
- FunctionARN: !GetAtt RewritePathFunction.FunctionARN
EventType: viewer-request
Lambda@Edge Functions
Resources:
# Lambda@Edge Function
LambdaEdgeFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "${AWS::StackName}-lambda-edge"
Code:
S3Bucket: !Ref CodeBucket
S3Key: lambda/edge-function.zip
Handler: index.handler
Runtime: nodejs20.x
Role: !GetAtt LambdaEdgeRole.Arn
# Lambda Version for Lambda@Edge
LambdaEdgeVersion:
Type: AWS::Lambda::Version
Properties:
FunctionName: !Ref LambdaEdgeFunction
Description: Lambda@Edge version
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: Origin
DomainName: !Ref OriginDomainName
CustomOriginConfig:
HTTPPort: 443
HTTPSPort: 443
OriginProtocolPolicy: https-only
DefaultCacheBehavior:
TargetOriginId: Origin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
LambdaFunctionAssociations:
- FunctionARN: !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${LambdaEdgeFunction}:${LambdaEdgeVersion}"
EventType: origin-request
Geo-Restrictions and Price Class
Resources:
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CallerReference: !Sub "${AWS::StackName}-${AWS::AccountId}"
Comment: !Sub "CloudFront with geo restrictions"
Enabled: true
IPV6Enabled: true
# Price Class - optimize costs
PriceClass: PriceClass_200
# Geo Restrictions
GeoRestriction:
RestrictionType: whitelist
Locations:
- US
- CA
- GB
- DE
- FR
- IT
- JP
- AU
Origins:
- Id: Origin
DomainName: !Ref OriginDomainName
CustomOriginConfig:
HTTPPort: 443
HTTPSPort: 443
OriginProtocolPolicy: https-only
DefaultCacheBehavior:
TargetOriginId: Origin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
Compress: true
ForwardedValues:
QueryString: false
Cookies:
Forward: none
MinTTL: 0
DefaultTTL: 86400
MaxTTL: 31536000
WAF Integration
Resources:
# WAF Web ACL
CloudFrontWebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: !Sub "${AWS::StackName}-waf-acl"
Scope: CLOUDFRONT
DefaultAction:
Allow: {}
Rules:
# AWS Managed Rule - Common
- Name: AWSCommonRule
Priority: 1
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesCommonRuleSet
ExcludedRules:
- Name: SizeRestrictions_BODY
OverrideAction:
None: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: AWSCommonRule
# Rate-based rule
- Name: RateLimitRule
Priority: 2
Statement:
RateBasedStatementKey:
SingleHeader:
Name: ip
AggregateKeyType: IP
Limit: 1000
OverrideAction:
None: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: RateLimitRule
# SQL Injection protection
- Name: SQLInjectionRule
Priority: 3
Statement:
SqliMatchStatement:
FieldToMatch:
QueryString: {}
UriPath: {}
TextTransformations:
- Priority: 1
Type: URL_DECODE
- Priority: 2
Type: LOWERCASE
OverrideAction:
None: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: SQLInjectionRule
# XSS protection
- Name: XSSRule
Priority: 4
Statement:
XssMatchStatement:
FieldToMatch:
QueryString: {}
UriPath: {}
TextTransformations:
- Priority: 1
Type: URL_DECODE
- Priority: 2
Type: LOWERCASE
OverrideAction:
None: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: XSSRule
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: CloudFrontWAFACL
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CallerReference: !Sub "${AWS::StackName}-${AWS::AccountId}"
Comment: !Sub "CloudFront with WAF"
Enabled: true
WebACLId: !GetAtt CloudFrontWebACL.Arn
Origins:
- Id: Origin
DomainName: !Ref OriginDomainName
CustomOriginConfig:
HTTPPort: 443
HTTPSPort: 443
OriginProtocolPolicy: https-only
DefaultCacheBehavior:
TargetOriginId: Origin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
ForwardedValues:
QueryString: false
Cookies:
Forward: none
MinTTL: 0
DefaultTTL: 86400
MaxTTL: 31536000
Real-Time Logs
Resources:
# Kinesis Data Stream
CloudFrontLogsStream:
Type: AWS::Kinesis::Stream
Properties:
Name: !Sub "${AWS::StackName}-cloudfront-logs"
ShardCount: 1
RetentionPeriodHours: 24
# IAM Role for CloudFront
CloudFrontLoggingRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${AWS::StackName}-cloudfront-logging"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: KinesisPutRecord
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- kinesis:PutRecord
- kinesis:PutRecords
Resource: !GetAtt CloudFrontLogsStream.Arn
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
CallerReference: !Sub "${AWS::StackName}-${AWS::AccountId}"
Comment: !Sub "CloudFront with real-time logs"
Enabled: true
RealTimeConfig:
Endpoint: !GetAtt CloudFrontLogsStream.Arn
RoleArn: !GetAtt CloudFrontLoggingRole.Arn
Fields:
- timestamp
- c-ip
- cs-method
- cs-uri
- sc-status
- time-taken
Origins:
- Id: Origin
DomainName: !Ref OriginDomainName
CustomOriginConfig:
HTTPPort: 443
HTTPSPort: 443
OriginProtocolPolicy: https-only
DefaultCacheBehavior:
TargetOriginId: Origin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
ForwardedValues:
QueryString: false
Cookies:
Forward: none
MinTTL: 0
DefaultTTL: 86400
MaxTTL: 31536000
Conditions and Transform
Conditions for Environment-Specific Configuration
AWSTemplateFormatVersion: 2010-09-09
Description: CloudFront with conditional configuration
Parameters:
Environment:
Type: String
Default: dev
AllowedValues:
- dev
- staging
- production
Description: Deployment environment
EnableWAF:
Type: String
Default: false
AllowedValues:
- true
- false
Description: Enable WAF protect
…(truncated)