home / skills / giuseppe-trisciuoglio / developer-kit / aws-cloudformation-cloudfront

This skill helps you define production CloudFront distributions with CloudFormation, multiple origins, caching, security headers, and cross-stack references.

npx playbooks add skill giuseppe-trisciuoglio/developer-kit --skill aws-cloudformation-cloudfront

Review the files below or copy the command above to add this skill to your agents.

Files (3)
SKILL.md
51.7 KB
---
name: aws-cloudformation-cloudfront
description: Provides AWS CloudFormation patterns for CloudFront distributions, origins (ALB, S3, Lambda@Edge, VPC Origins), CacheBehaviors, Functions, SecurityHeaders, parameters, Outputs and cross-stack references. Use when creating CloudFront distributions with CloudFormation, configuring multiple origins, implementing caching strategies, managing custom domains with ACM, configuring WAF, and optimizing performance.
category: aws
tags: [aws, cloudformation, cloudfront, cdn, content-delivery, distributions, origins, cache, waf, security]
version: 1.0.0
allowed-tools: Read, Write, Bash
---

# 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:

1. **Define Distribution Parameters**: Specify domain names, ACM certificates, and price class
2. **Configure Origins**: Add S3 buckets, ALBs, API Gateway, or custom origins
3. **Set Up Default Cache Behavior**: Configure viewer request/response policies
4. **Add Additional Cache Behaviors**: Create path-specific caching rules
5. **Configure Security Settings**: Implement security headers and WAF integration
6. **Add Lambda@Edge Functions**: Configure functions for request/response manipulation
7. **Set Up Custom Error Pages**: Define error responses for specific HTTP status codes
8. **Create Monitoring**: Configure logging and access logs to S3

For complete examples, see the [EXAMPLES.md](references/examples.md) file.

## Examples

The following examples demonstrate common CloudFront patterns:

### Example 1: CloudFront Distribution with S3 Origin

```yaml
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

```yaml
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

```yaml
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](references/examples.md).

## CloudFormation Template Structure

### Standard Format Base Template

```yaml
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

```yaml
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

```yaml
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

```yaml
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

```yaml
# 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"
```

```yaml
# 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

```yaml
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

```yaml
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)

```yaml
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

```yaml
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

```yaml
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

```yaml
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

```yaml
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

```yaml
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)

```yaml
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

```yaml
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

```yaml
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

```yaml
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

```yaml
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

```yaml
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

```yaml
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 protection

Conditions:
  IsProduction: !Equals [!Ref Environment, production]
  IsStaging: !Equals [!Ref Environment, staging]
  EnableWAFProtection: !And
    - !Equals [!Ref EnableWAF, true]
    - !Or
      - [!Equals [!Ref Environment, staging]]
      - [!Equals [!Ref Environment, production]]

Resources:
  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        CallerReference: !Sub "${AWS::StackName}-${AWS::AccountId}"
        Comment: !Sub "CloudFront for ${Environment}"
        Enabled: true
        IPV6Enabled: true
        PriceClass: !If [IsProduction, PriceClass_All, PriceClass_100]
        WebACLId: !If [EnableWAFProtection, !Ref CloudFrontWebACL, !Ref AWS::NoValue]
        Origins:
          - Id: Origin
            DomainName: !Ref OriginDomainName
            CustomOriginConfig:
              HTTPPort: 443
              HTTPSPort: 443
              OriginProtocolPolicy: https-only
        DefaultCacheBehavior:
          TargetOriginId: Origin
          ViewerProtocolPolicy: !If [IsProduction, redirect-to-https, allow-all]
          AllowedMethods:
            - GET
            - HEAD
          CachedMethods:
            - GET
            - HEAD
          Compress: !If [IsProduction, true, false]
          ForwardedValues:
            QueryString: false
            Cookies:
              Forward: none
          MinTTL: !If [IsProduction, 0, 0]
          DefaultTTL: !If [IsProduction, 86400, 3600]
          MaxTTL: !If [IsProduction, 31536000, 86400]

  # WAF only for staging and production
  CloudFrontWebACL:
    Type: AWS::WAFv2::WebACL
    Condition: EnableWAFProtection
    Properties:
      Name: !Sub "${AWS::StackName}-waf-acl"
      Scope: CLOUDFRONT
      DefaultAction:
        Allow: {}
      Rules: []
      VisibilityConfig:
        SampledRequestsEnabled: true
        CloudWatchMetricsEnabled: true
        MetricName: CloudFrontWAFACL
```

## VPC Origins

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: CloudFront with VPC Origin

Resources:
  # VPC Origin Endpoint
  VPCOriginEndpoint:
    Type: AWS::GlobalAccelerator::EndpointGroup
    Properties:
      EndpointGroupRegion: !Ref VPCOriginRegion
      ListenerArn: !Ref AcceleratorListener
      EndpointConfigurations:
        - EndpointId: !Ref VPCEndpointService
          Weight: 128

  # CloudFront Distribution
  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        CallerReference: !Sub "${AWS::StackName}-${AWS::AccountId}"
        Comment: !Sub "CloudFront with VPC Origin"
        Enabled: true
        IPV6Enabled: true
        Origins:
          - Id: VPCOrigin
            DomainName: !Ref VPCOriginDomain
            CustomOriginConfig:
              HTTPPort: 443
              HTTPSPort: 443
              OriginProtocolPolicy: https-only
              OriginKeepaliveTimeout: 60
              OriginReadTimeout: 30
        DefaultCacheBehavior:
          TargetOriginId: VPCOrigin
          ViewerProtocolPolicy: https-only
          AllowedMethods:
            - GET
            - HEAD
            - OPTIONS
          CachedMethods:
            - GET
            - HEAD
          Compress: true
          ForwardedValues:
            QueryString: true
            Headers:
              - "*"
            Cookies:
              Forward: all
          MinTTL: 0
          DefaultTTL: 3600
          MaxTTL: 86400
```

## Best Practices

### Security

- Always use HTTPS with minimum TLS 1.2
- Implement SecurityHeaders with HSTS, XSS protection
- Use WAF for protection against common attacks
- Configure appropriate Access-Control for CORS
- Limit origin access with OAI/OAC
- Use Signed URLs for private content
- Implement rate limiting
- Configure geo-restrictions if needed

### Performance

- Use appropriate PriceClass to optimize costs
- Configure Cache TTL based on content type
- Enable compression (Gzip/Brotli)
- Use CloudFront Functions for lightweight operations
- Optimize header forwarding (do not forward unnecessary headers)
- Consider Origin Shield to reduce load on origins
- Use multiple origins with path patterns

### Monitoring

- Enable CloudWatch metrics and alarms
- Configure real-time logs for troubleshooting
- Monitor cache hit ratio
- Configure alerts for error rate and latency
- Use CloudFront reports for traffic analysis

### Deployment

- Use change sets before deployment
- Test templates with cfn-lint
- Organize stacks by lifecycle and ownership
- Implement blue/green deployments with weighted aliases
- Use StackSets for multi-region deployment


## CloudFormation Best Practices

### Stack Policies

Stack Policies prevent accidental updates to critical resources during stack updates.

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: CloudFront distribution with stack policy

Resources:
  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Enabled: true
        # ... configuration

  CloudFrontWebACL:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: !Sub "${AWS::StackName}-waf"
      Scope: CLOUDFRONT
      DefaultAction:
        Allow: {}
      Rules: []
      VisibilityConfig:
        SampledRequestsEnabled: true
        CloudWatchMetricsEnabled: true
        MetricName: CloudFrontWAF

# Stack Policy - protect critical resources
Metadata:
  AWS::CloudFormation::StackPolicy:
    Statement:
      - Effect: Allow
        Action: Update:*
        Resource: "*"
      - Effect: Deny
        Action:
          - Update:Replace
          - Update:Delete
        Resource: "LogicalID=CloudFrontDistribution"
        Principal: "*"
      - Effect: Deny
        Action:
          - Update:Replace
          - Update:Delete
        Resource: "LogicalID=CloudFrontWebACL"
        Principal: "*"
```

### Termination Protection

Enable termination protection to prevent accidental stack deletion.

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: CloudFront with termination protection

Resources:
  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Enabled: true
        # ... configuration

# Note: Termination protection is enabled via AWS Console or CLI
# AWS CLI: aws cloudformation update-termination-protection --enable-termination-protection --stack-name my-stack
# Or set it in a separate stack update after creation
```

### Drift Detection

Detect when infrastructure has been modified outside of CloudFormation.

```yaml
# AWS CLI commands for drift detection
# Detect drift on a stack
aws cloudformation detect-stack-drift --stack-name my-cloudfront-stack

# Get drift detection status
aws cloudformation describe-stack-drift-detection-status --stack-drift-detection-id <detection-id>

# Get resources that have drifted
aws cloudformation describe-stack-resource-drifts --stack-name my-cloudfront-stack

# Example drift detection output format
# {
#     "StackResourceDrifts": [
#         {
#             "ResourceType": "AWS::CloudFront::Distribution",
#             "LogicalResourceId": "CloudFrontDistribution",
#             "PhysicalResourceId": "E1X2Y3Z4W5X6Y7",
#             "ResourceStatus": "UPDATE",
#             "PropertyDifferences": [
#                 {
#                     "PropertyPath": "$.DistributionConfig.Enabled",
#                     "ExpectedValue": "true",
#                     "ActualValue": "false"
#                 }
#             ],
#             "StackResourceDriftStatus": "MODIFIED"
#         }
#     ]
# }
```

### Change Sets

Preview and review changes before executing stack updates.

```yaml
# AWS CLI commands for change sets

# 1. Create a change set (preview)
aws cloudformation create-change-set \
  --stack-name my-cloudfront-stack \
  --template-body file://cloudfront-template.yaml \
  --change-set-name my-changeset \
  --capabilities CAPABILITY_IAM \
  --parameters ParameterKey=Environment,ParameterValue=production

# 2. Describe the change set to review changes
aws cloudformation describe-change-set \
  --stack-name my-cloudfront-stack \
  --change-set-name my-changeset

# 3. Execute the change set if changes are acceptable
aws cloudformation execute-change-set \
  --stack-name my-cloudfront-stack \
  --change-set-name my-changeset

# Or delete if changes are not desired
aws cloudformation delete-change-set \
  --stack-name my-cloudfront-stack \
  --change-set-name my-changeset
```

```yaml
# Change set with nested stacks example
AWSTemplateFormatVersion: 2010-09-09
Description: CloudFront infrastructure with nested stacks for change set management

Resources:
  # Parent stack managing multiple CloudFront distributions
  CloudFrontParentStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Sub "https://${ArtifactBucket}.s3.amazonaws.com/cloudfront-parent.yaml"
      TimeoutInMinutes: 30
      Parameters:
        Environment: !Ref Environment
        CertificateArn: !Ref CertificateArn
        DomainName: !Ref DomainName
      Tags:
        - Key: Environment
          Value: !Ref Environment
        - Key: Project
          Value: !Ref ProjectName
        - Key: ManagedBy
          Value: CloudFormation

  # Change set will show impacts across all nested stacks
  # When updating, CloudFormation will show:
  # - Which nested stacks will be updated
  # - Resources being added, modified, or deleted
  # - IAM changes requiring special attention
```

## Related Resources

- [AWS CloudFront Documentation](https://docs.aws.amazon.com/cloudfront/)
- [AWS CloudFormation User Guide](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/)
- [CloudFront Developer Guide](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/)
- [CloudFront Best Practices](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html)
- [CloudFormation Stack Policies](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/protect-stack-resources.html)
- [CloudFormation Drift Detection](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/detect-drift-stack.html)
- [CloudFormation Change Sets](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-changesets.html)

## Constraints and Warnings

### Resource Limits

- **Distribution Limits**: Maximum 200 CloudFront distributions per AWS account
- **Origins Limits**: Maximum 25 origins per distribution
- **Cache Behaviors**: Maximum 25 cache behaviors per distribution
- **Custom Headers**: Maximum 10 custom headers per origin

### DNS and Certificate Constraints

- **Domain Registration**: Custom domains must be registered and verified before use
- **ACM Certificate Limits**: Certificates must be in us-east-1 for CloudFront regardless of distribution region
- **DNS Propagation**: DNS changes can take up to 24 hours to propagate globally
- **Alternate Domain Names**: Maximum 300 alternate domain names per distribution

### Operational Constraints

- **Invalidation Limits**: Maximum 15 invalidation requests in progress at once
- **Deployment Time**: Distribution deployment can take up to 30 minutes
- **Edge Location Caching**: Changes at origins may not be reflected immediately due to caching
- **Geo Restriction Accuracy**: Geo restriction based on IP addresses may not be 100% accurate

### Security Constraints

- **HTTPS Only**: Modern browsers block HTTP-only content on HTTPS pages
- **CSP Headers**: Content Security Policy headers can break functionality if misconfigured
- **WAF Integration**: WAF rules add latency and may block legitimate traffic
- **Origin Access**: OAI/OAC restrictions prevent direct S3 access but complicate testing

### Cost Considerations

- **Data Transfer Out**: CloudFront charges for data transfer out to internet
- **Regional Pricing**: Costs vary significantly by edge location
- **HTTPS Requests**: Encrypted requests have higher CPU utilization cost
- **Lambda@Edge**: Lambda@Edge functions add significant per-invocation cost

## Additional Files

For complete details on resources and their properties, see:
- [REFERENCE.md](references/reference.md) - Detailed reference guide for all CloudFormation resources
- [EXAMPLES.md](references/examples.md) - Complete production-ready examples

Overview

This skill provides production-ready AWS CloudFormation patterns for creating and managing CloudFront distributions and related resources. I include templates and examples for multiple origin types, cache behaviors, security headers, Lambda@Edge/Functions, ACM integration, WAF, and cross-stack exports. The goal is to help you declare CDN infrastructure reliably and reuseable across stacks and environments.

How this skill works

I supply CloudFormation snippets and full template structures that define DistributionConfig, Origins (S3, ALB, API Gateway, VPC, Lambda@Edge), CachePolicy and OriginRequestPolicy resources, and ViewerCertificate settings for custom domains. The skill shows parameter typing, constraints, SSM lookups, outputs and export/import patterns, plus examples for security headers, error pages, logging and nested stacks for modular deployments. Use the patterns to wire ACM certificates, OAI, WAF associations, caching strategies and monitoring into repeatable templates.

When to use it

  • Creating new CloudFront distributions with CloudFormation for production workloads
  • Configuring multiple origin types (S3, ALB, API Gateway, Lambda@Edge, VPC Origins)
  • Implementing fine-grained caching using CacheBehaviors, CachePolicy and OriginRequestPolicy
  • Managing custom domains with ACM and SNI-based viewer certificates
  • Integrating WAF, security headers, and Lambda@Edge or CloudFront Functions for request/response logic
  • Sharing resources between stacks with export/import or nested stacks for modular deployments

Best practices

  • Use AWS-specific parameter types (Certificate ARN, S3 bucket types, ALB DNS/ARN) to validate inputs and enable safer deployments
  • Centralize reusable configs (cache policies, origin request policies, security header functions) and export them from an infrastructure stack
  • Default to TLSv1.2_2021, enable IPv6 and HTTP/2/3, and set sensible Default/Max/Min TTLs to balance performance and invalidation cost
  • Limit forwarded headers/cookies/queries in cache keys to maximize cache hit ratio; whitelist only what your origin needs
  • Store WAF WebACL ARNs and CloudFront key IDs in SSM and reference them in templates for safer environment configuration

Example use cases

  • Static website delivery: CloudFront + S3 origin with OAI, long TTLs, and security headers enforced via CloudFront Functions
  • API fronting: CloudFront in front of ALB or API Gateway with path-based CacheBehaviors and origin request policy that forwards auth headers
  • Edge logic: Lambda@Edge or CloudFront Functions to rewrite requests, inject security headers, or perform A/B routing
  • Multi-stack deployment: Export S3 bucket and OAI from a network/infrastructure stack and import them into application stacks that create distributions
  • Modular templates: Use nested stacks for separate static asset and API distributions to improve CI/CD and deployment isolation

FAQ

Can I use ACM certificates in any region for CloudFront?

ACM certificates for CloudFront must be in us-east-1; include region-aware mappings or request the certificate in us-east-1 and reference its ARN in the template.

How do I protect S3 origins behind CloudFront?

Create an Origin Access Identity (OAI) or Origin Access Control, restrict S3 bucket policy to allow only CloudFront, and reference the OAI in the S3OriginConfig.

When should I use Lambda@Edge vs CloudFront Functions?

Use CloudFront Functions for lightweight, high-performance request/response header manipulation and routing. Use Lambda@Edge for more complex logic, custom authentication, or when you need Node/Python runtime features.