Setting up AWS CloudFront with Terraform

A comprehensive guide to deploying and configuring Amazon CloudFront CDN using Terraform Infrastructure as Code

Setting up AWS CloudFront with Terraform

Amazon CloudFront is a fast content delivery network (CDN) service that securely delivers data, videos, applications, and APIs to customers globally. This guide shows how to set up CloudFront using Terraform.

Video Tutorial

Learn more about managing AWS CloudFront with Terraform in this comprehensive video tutorial:

View Source Code

Prerequisites

  • AWS CLI configured
  • Terraform installed
  • S3 bucket or origin server ready
  • SSL certificate (optional)
  • Basic understanding of CDN concepts

Project Structure

aws-cloudfront-terraform/
├── main.tf
├── variables.tf
├── outputs.tf
└── terraform.tfvars

Basic CloudFront Configuration

# main.tf
provider "aws" {
  region = var.aws_region
}

# CloudFront distribution
resource "aws_cloudfront_distribution" "s3_distribution" {
  enabled             = true
  is_ipv6_enabled    = true
  comment            = "My CloudFront Distribution"
  default_root_object = "index.html"
  price_class        = "PriceClass_100"

  # Origin configuration
  origin {
    domain_name = aws_s3_bucket.website.bucket_regional_domain_name
    origin_id   = "S3-${aws_s3_bucket.website.id}"

    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.oai.cloudfront_access_identity_path
    }
  }

  # Default cache behavior
  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD", "OPTIONS"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "S3-${aws_s3_bucket.website.id}"

    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "redirect-to-https"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 86400
  }

  # Restrictions
  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  # SSL certificate
  viewer_certificate {
    cloudfront_default_certificate = true
  }

  tags = {
    Environment = var.environment
  }
}

# Origin Access Identity
resource "aws_cloudfront_origin_access_identity" "oai" {
  comment = "OAI for ${var.project_name}"
}

Custom Domain and SSL Configuration

resource "aws_cloudfront_distribution" "custom_domain" {
  # ... other configuration ...

  aliases = ["cdn.${var.domain_name}"]

  viewer_certificate {
    acm_certificate_arn      = aws_acm_certificate.cert.arn
    minimum_protocol_version = "TLSv1.2_2021"
    ssl_support_method       = "sni-only"
  }
}

# ACM Certificate
resource "aws_acm_certificate" "cert" {
  provider          = aws.us-east-1  # CloudFront requires certificates in us-east-1
  domain_name       = "cdn.${var.domain_name}"
  validation_method = "DNS"

  tags = {
    Environment = var.environment
  }

  lifecycle {
    create_before_destroy = true
  }
}

Custom Cache Behaviors

resource "aws_cloudfront_distribution" "custom_behaviors" {
  # ... other configuration ...

  # API path pattern
  ordered_cache_behavior {
    path_pattern     = "/api/*"
    allowed_methods  = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = var.api_origin_id

    forwarded_values {
      query_string = true
      headers      = ["Authorization"]

      cookies {
        forward = "all"
      }
    }

    viewer_protocol_policy = "https-only"
    min_ttl                = 0
    default_ttl            = 0
    max_ttl                = 0
  }

  # Static assets pattern
  ordered_cache_behavior {
    path_pattern     = "/static/*"
    allowed_methods  = ["GET", "HEAD", "OPTIONS"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = var.static_origin_id

    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "redirect-to-https"
    min_ttl                = 0
    default_ttl            = 86400    # 24 hours
    max_ttl                = 31536000 # 1 year
  }
}

Function Associations

# CloudFront Function
resource "aws_cloudfront_function" "url_rewrite" {
  name    = "url-rewrite"
  runtime = "cloudfront-js-1.0"
  comment = "URL rewrite function"
  publish = true
  code    = file("${path.module}/functions/url-rewrite.js")
}

resource "aws_cloudfront_distribution" "with_functions" {
  # ... other configuration ...

  default_cache_behavior {
    # ... other settings ...

    function_association {
      event_type   = "viewer-request"
      function_arn = aws_cloudfront_function.url_rewrite.arn
    }
  }
}

Variables Configuration

# variables.tf
variable "aws_region" {
  description = "AWS region"
  type        = string
  default     = "us-west-2"
}

variable "project_name" {
  description = "Project name"
  type        = string
}

variable "domain_name" {
  description = "Domain name"
  type        = string
}

variable "environment" {
  description = "Environment name"
  type        = string
  default     = "production"
}

variable "price_class" {
  description = "CloudFront distribution price class"
  type        = string
  default     = "PriceClass_100"
}

Best Practices

  1. Performance

    • Use appropriate cache behaviors
    • Configure proper TTL values
    • Enable compression
    • Use modern TLS versions
  2. Security

    • Use Origin Access Identity for S3
    • Implement proper WAF rules
    • Use custom SSL certificates
    • Configure security headers
  3. Cost Optimization

    • Choose appropriate price class
    • Use cache effectively
    • Monitor usage patterns
    • Clean up unused distributions
  4. Monitoring

    • Set up CloudWatch alarms
    • Monitor cache hit ratios
    • Track error rates
    • Enable access logging

WAF Configuration

resource "aws_wafv2_web_acl" "cloudfront" {
  name        = "${var.project_name}-waf"
  description = "WAF for CloudFront distribution"
  scope       = "CLOUDFRONT"

  default_action {
    allow {}
  }

  rule {
    name     = "AWSManagedRulesCommonRuleSet"
    priority = 1

    override_action {
      none {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesCommonRuleSet"
        vendor_name = "AWS"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = true
      metric_name               = "AWSManagedRulesCommonRuleSetMetric"
      sampled_requests_enabled  = true
    }
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name               = "CloudFrontWAFMetric"
    sampled_requests_enabled  = true
  }
}

Deployment Steps

  1. Initialize Terraform:
terraform init
  1. Plan the deployment:
terraform plan
  1. Apply the configuration:
terraform apply

Clean Up

Remove all resources when done:

terraform destroy

Common Use Cases

  1. Static Website Hosting
resource "aws_cloudfront_distribution" "website" {
  # ... other configuration ...

  custom_error_response {
    error_code         = 404
    response_code      = 200
    response_page_path = "/index.html"
  }

  custom_error_response {
    error_code         = 403
    response_code      = 200
    response_page_path = "/index.html"
  }
}
  1. API Gateway Integration
resource "aws_cloudfront_distribution" "api" {
  # ... other configuration ...

  origin {
    domain_name = replace(aws_apigatewayv2_api.main.api_endpoint, "https://", "")
    origin_id   = "ApiGateway"

    custom_origin_config {
      http_port              = 80
      https_port             = 443
      origin_protocol_policy = "https-only"
      origin_ssl_protocols   = ["TLSv1.2"]
    }
  }
}

Conclusion

This setup provides a comprehensive foundation for deploying CloudFront using Terraform. Remember to:

  • Plan your CDN architecture carefully
  • Implement proper security measures
  • Monitor performance and costs
  • Keep your configurations versioned
  • Test thoroughly before production deployment

The complete code can be customized based on your specific requirements and use cases.