AWS CDN Complete Implementation Guide - Kubernetes + CloudFront for API and Static File Optimization

Building scalable CDN solutions with External-DNS, ALB, S3, and CloudFront for global content delivery

Featured image


aws-cdn-kubernetes-s3-2


Overview

Content Delivery Networks (CDN) have evolved from optional infrastructure to mission-critical components in modern web applications.

For organizations operating global services or handling high-volume traffic, a well-architected CDN strategy is essential for maintaining user experience and server stability.

This comprehensive guide demonstrates how to build a complete CDN solution using Kubernetes and AWS CloudFront, optimizing both API server responses and static file delivery.

We’ll cover automated DNS management with External-DNS, dual distribution patterns (ALB + CloudFront and S3 + CloudFront), and enterprise-grade security configurations.


Architecture Overview

Our CDN implementation follows a hybrid architecture pattern that addresses different content delivery requirements through specialized distribution strategies.

graph TB subgraph "Client Layer" Users[Global Users] Mobile[Mobile Apps] Web[Web Browsers] end subgraph "DNS Layer" Route53[Route53 DNS] ExternalDNS[External-DNS Controller] end subgraph "CDN Layer" APICF[API CloudFront Distribution] StaticCF[Static Files CloudFront Distribution] end subgraph "Origin Layer - API" ALB[Application Load Balancer] K8sCluster[Kubernetes Cluster] APIServices[API Services] end subgraph "Origin Layer - Static" S3[S3 Bucket] StaticFiles[Static Files Storage] end subgraph "Security & Monitoring" WAF[AWS WAF] ACM[ACM Certificates] CloudWatch[CloudWatch Monitoring] end Users --> Route53 Mobile --> Route53 Web --> Route53 Route53 --> APICF Route53 --> StaticCF APICF --> ALB StaticCF --> S3 ALB --> K8sCluster K8sCluster --> APIServices S3 --> StaticFiles ExternalDNS --> Route53 ExternalDNS --> K8sCluster WAF --> APICF WAF --> StaticCF ACM --> APICF ACM --> StaticCF CloudWatch --> APICF CloudWatch --> StaticCF CloudWatch --> ALB


Dual Distribution Strategy

API Server CDN (ALB + CloudFront): Dynamic content with intelligent caching based on endpoint characteristics

Static File CDN (S3 + CloudFront): Long-term cached static assets with optimized compression and security


Component Architecture


API Server CDN Flow

  1. Kubernetes Cluster: Application runtime environment with horizontal pod autoscaling
  2. External-DNS: Automated Route53 record management for service discovery
  3. Application Load Balancer: Origin server with health checks and SSL termination
  4. CloudFront Distribution: Global edge caching with path-based cache behaviors

Static File CDN Flow

  1. S3 Bucket: Secure storage with versioning and lifecycle policies
  2. Origin Access Control: Zero-trust security model for S3 access
  3. CloudFront Distribution: Global distribution with file-type optimized caching
  4. Route53 Integration: DNS alias records for custom domain routing


Step 1: External-DNS Configuration

External-DNS serves as the automation backbone for DNS management, automatically creating and updating Route53 records based on Kubernetes resource annotations.

# external-dns-values.yaml
image:
  repository: registry.k8s.io/external-dns/external-dns
  pullPolicy: IfNotPresent

serviceAccount:
  create: true
  annotations:
    # IRSA (IAM Role for Service Account) configuration
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/external-dns-role

# Deploy to system-dedicated nodegroup for stability
nodeSelector:
  eks.amazonaws.com/nodegroup: system-nodegroup

# Security hardening - principle of least privilege
podSecurityContext:
  runAsNonRoot: true
  fsGroup: 65534

securityContext:
  privileged: false
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  runAsNonRoot: true
  runAsUser: 65532
  runAsGroup: 65532
  capabilities:
    drop: ["ALL"]

rbac:
  create: true

# Resource optimization
resources:
  requests:
    cpu: 50m
    memory: 64Mi
  limits:
    cpu: 200m
    memory: 256Mi

# Logging and monitoring configuration
logLevel: info
logFormat: text
interval: 5m

# Resource types to monitor
sources:
  - service
  - ingress

# DNS record management policy
policy: upsert-only  # Safe record management
registry: txt
txtOwnerId: "enterprise-external-dns"
txtPrefix: "external-dns-"

# Domain filtering for security
domainFilters:
  - enterprise.example.com

# AWS Route53 provider configuration
provider:
  name: aws

extraArgs:
  - --aws-zone-type=public
  - --aws-prefer-cname
  - --annotation-filter=external-dns.alpha.kubernetes.io/hostname


Step 2: ACM Certificate Generation for CloudFront

CloudFront requires certificates specifically issued in the us-east-1 region. We’ll use Terraform to provision certificates with proper validation.

# acm-certificates.tf
module "cloudfront_certificate" {
  source = "../../../modules/acm/v6.1.0"

  providers = {
    aws = aws.us_east_1  # CloudFront certificates must be in us-east-1
  }

  domain_name       = var.root_domain
  zone_id           = aws_route53_zone.main_zone.zone_id
  validation_method = "DNS"

  subject_alternative_names = [
    "*.enterprise.example.com",
    "enterprise.example.com"
  ]

  wait_for_validation = true

  tags = {
    Environment = var.environment
    Project     = var.project
    Terraform   = var.terraform
    Purpose     = "CloudFront-SSL"
    Name        = "cloudfront-acm-certificate"
  }

  depends_on = [aws_route53_zone.main_zone]
}


Step 3: API Origin Server Setup

Creating dedicated origin domains separates CDN traffic from direct access, enabling better traffic analysis and security controls.

# api-ingress-values.yaml
ingress:
  enabled: true
  className: "alb"
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    
    # Shared ALB group for cost optimization
    alb.ingress.kubernetes.io/group.name: enterprise-shared-alb
    alb.ingress.kubernetes.io/group.order: "10"
    
    # Origin-specific domain configuration
    external-dns.alpha.kubernetes.io/hostname: origin-api.enterprise.example.com
    
    # Explicit ALB naming
    alb.ingress.kubernetes.io/load-balancer-name: enterprise-shared-alb-loadbalancer
    
    # SSL configuration (ALB - service region certificate)
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:eu-central-1:123456789012:certificate/cert-id
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]'  # HTTPS only
    
    # ALB optimization for CDN
    alb.ingress.kubernetes.io/target-group-attributes: |
      deregistration_delay.timeout_seconds=30,
      stickiness.enabled=false
      
    # Purpose identification through tagging
    alb.ingress.kubernetes.io/tags: "Purpose=CDN-Origin,Environment=production"
    
  hosts:
    - host: origin-api.enterprise.example.com
      paths:
        - path: /
          pathType: Prefix


Step 4: API CloudFront Distribution Configuration

The API distribution requires sophisticated caching strategies that account for different endpoint characteristics and data sensitivity levels.

# cloudfront-api.tf
module "api_cdn" {
  source = "terraform-aws-modules/cloudfront/aws"

  aliases = ["api.enterprise.example.com"]
  comment = "Enterprise API CloudFront Distribution"
  
  enabled             = true
  is_ipv6_enabled     = true
  price_class         = "PriceClass_100"  # North America, Europe focused
  retain_on_delete    = false
  wait_for_deployment = false

  # ALB Origin configuration
  origin = {
    alb_api_origin = {
      domain_name = "origin-api.enterprise.example.com"
      custom_origin_config = {
        http_port                = 443
        https_port               = 443
        origin_protocol_policy   = "https-only"
        origin_ssl_protocols     = ["TLSv1.2"]
        origin_read_timeout      = 60
        origin_keepalive_timeout = 5
      }
      
      # Origin Shield for improved cache hit ratio
      origin_shield = {
        enabled              = true
        origin_shield_region = "eu-central-1"  # Match service region
      }
    }
  }

  # Default cache behavior - general API responses
  default_cache_behavior = {
    target_origin_id       = "alb_api_origin"
    viewer_protocol_policy = "redirect-to-https"
    allowed_methods        = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods         = ["GET", "HEAD", "OPTIONS"]
    compress               = true

    use_forwarded_values = true
    query_string         = true
    headers              = ["Host", "Origin", "Referer", "CloudFront-Forwarded-Proto"]
    cookies_forward      = "none"

    min_ttl     = 0
    default_ttl = 3600   # 1 hour default cache
    max_ttl     = 86400  # Maximum 24 hours
  }

  # Endpoint-specific cache control
  ordered_cache_behavior = [
    # Health checks - short cache for rapid failure detection
    {
      path_pattern           = "/health"
      target_origin_id       = "alb_api_origin"
      viewer_protocol_policy = "redirect-to-https"
      allowed_methods        = ["GET", "HEAD", "OPTIONS"]
      cached_methods         = ["GET", "HEAD"]
      compress               = true

      use_forwarded_values = true
      query_string         = false
      headers              = ["Host"]
      cookies_forward      = "none"

      min_ttl     = 0
      default_ttl = 30     # 30 seconds
      max_ttl     = 300    # Maximum 5 minutes
    },
    
    # Static configuration data - medium cache duration
    {
      path_pattern           = "/api/configs/*"
      target_origin_id       = "alb_api_origin"
      viewer_protocol_policy = "redirect-to-https"
      allowed_methods        = ["GET", "HEAD", "OPTIONS"]
      cached_methods         = ["GET", "HEAD"]
      compress               = true

      use_forwarded_values = true
      query_string         = true
      headers              = ["Host", "Authorization", "Content-Type"]
      cookies_forward      = "all"

      min_ttl     = 0
      default_ttl = 1800   # 30 minutes
      max_ttl     = 3600   # 1 hour
    },
    
    # Product listings - considering change frequency
    {
      path_pattern           = "/api/products/list"
      target_origin_id       = "alb_api_origin"
      viewer_protocol_policy = "redirect-to-https"
      allowed_methods        = ["GET", "HEAD", "OPTIONS"]
      cached_methods         = ["GET", "HEAD"]
      compress               = true

      use_forwarded_values = true
      query_string         = true
      headers              = ["Host", "Authorization"]
      cookies_forward      = "all"

      min_ttl     = 0
      default_ttl = 900    # 15 minutes
      max_ttl     = 1800   # 30 minutes
    },
    
    # Authentication endpoints - cache completely disabled
    {
      path_pattern           = "/auth/*"
      target_origin_id       = "alb_api_origin"
      viewer_protocol_policy = "redirect-to-https"
      allowed_methods        = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
      cached_methods         = ["GET", "HEAD"]
      compress               = true

      use_forwarded_values = true
      query_string         = true
      headers              = ["*"]  # Forward all headers
      cookies_forward      = "all"

      min_ttl     = 0
      default_ttl = 0      # No caching
      max_ttl     = 0
    },
    
    # User-specific data - cache disabled
    {
      path_pattern           = "/api/users/*"
      target_origin_id       = "alb_api_origin"
      viewer_protocol_policy = "redirect-to-https"
      allowed_methods        = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
      cached_methods         = ["GET", "HEAD"]
      compress               = true

      use_forwarded_values = true
      query_string         = true
      headers              = ["*"]
      cookies_forward      = "all"

      min_ttl     = 0
      default_ttl = 0
      max_ttl     = 0
    }
  ]

  # SSL certificate configuration
  viewer_certificate = {
    acm_certificate_arn      = module.cloudfront_certificate.acm_certificate_arn
    ssl_support_method       = "sni-only"
    minimum_protocol_version = "TLSv1.2_2021"
  }

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

  # SPA support through error page handling
  custom_error_response = [
    {
      error_code         = 404
      response_code      = 200
      response_page_path = "/index.html"
    }
  ]

  tags = {
    Environment = var.environment
    Project     = var.project
    Terraform   = var.terraform
    Name        = "enterprise-api-cdn"
    Purpose     = "API-Distribution"
  }

  depends_on = [module.cloudfront_certificate]
}


Step 5: Route53 DNS Configuration

Comprehensive DNS setup supporting both IPv4 and IPv6 for maximum global accessibility.

# route53.tf
resource "aws_route53_zone" "main_zone" {
  name = var.domain_name

  tags = {
    Environment = var.environment
    Project     = var.project
    Terraform   = var.terraform
    Name        = "main-route53-zone"
  }
}

# API CDN A record (IPv4)
resource "aws_route53_record" "api_cdn" {
  zone_id = aws_route53_zone.main_zone.zone_id
  name    = "api.enterprise.example.com"
  type    = "A"

  alias {
    name                   = module.api_cdn.cloudfront_distribution_domain_name
    zone_id                = module.api_cdn.cloudfront_distribution_hosted_zone_id
    evaluate_target_health = false
  }

  depends_on = [
    aws_route53_zone.main_zone,
    module.api_cdn
  ]
}

# API CDN AAAA record (IPv6)
resource "aws_route53_record" "api_cdn_ipv6" {
  zone_id = aws_route53_zone.main_zone.zone_id
  name    = "api.enterprise.example.com"
  type    = "AAAA"

  alias {
    name                   = module.api_cdn.cloudfront_distribution_domain_name
    zone_id                = module.api_cdn.cloudfront_distribution_hosted_zone_id
    evaluate_target_health = false
  }

  depends_on = [
    aws_route53_zone.main_zone,
    module.api_cdn
  ]
}

# Static files CDN A record (IPv4)
resource "aws_route53_record" "static_files_cdn" {
  zone_id = aws_route53_zone.main_zone.zone_id
  name    = "cdn.enterprise.example.com"
  type    = "A"

  alias {
    name                   = module.static_files_cdn.cloudfront_distribution_domain_name
    zone_id                = module.static_files_cdn.cloudfront_distribution_hosted_zone_id
    evaluate_target_health = false
  }

  depends_on = [
    aws_route53_zone.main_zone,
    module.static_files_cdn
  ]
}

# Static files CDN AAAA record (IPv6)
resource "aws_route53_record" "static_files_cdn_ipv6" {
  zone_id = aws_route53_zone.main_zone.zone_id
  name    = "cdn.enterprise.example.com"
  type    = "AAAA"

  alias {
    name                   = module.static_files_cdn.cloudfront_distribution_domain_name
    zone_id                = module.static_files_cdn.cloudfront_distribution_hosted_zone_id
    evaluate_target_health = false
  }

  depends_on = [
    aws_route53_zone.main_zone,
    module.static_files_cdn
  ]
}


IPv6 Support Benefits

Benefit Technical Advantage Business Impact
Address Space Unlimited addressing vs IPv4 exhaustion Future-proof infrastructure design
Performance No NAT overhead, direct routing Lower latency for mobile users
Global Reach High adoption in APAC regions Better user experience in key markets
Mobile Networks LTE/5G prefer IPv6 Optimized mobile application performance


Step 6: S3 Static File Storage Configuration

Implementing zero-trust security model with Origin Access Control for maximum protection.

# s3-static-files.tf
module "static_files_bucket" {
  source = "terraform-aws-modules/s3-bucket/aws"

  bucket = var.static_files_bucket_name

  # Private bucket with complete isolation
  control_object_ownership = true
  object_ownership         = "ObjectWriter"

  # Block all public access (security hardening)
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true

  # Server-side encryption configuration
  server_side_encryption_configuration = {
    rule = {
      apply_server_side_encryption_by_default = {
        sse_algorithm = "AES256"
      }
    }
  }

  # Versioning for file recovery and change tracking
  versioning = {
    enabled = true
  }

  # Lifecycle management for cost optimization
  lifecycle_configuration = {
    rule = [
      {
        id     = "delete_old_versions"
        status = "Enabled"
        
        noncurrent_version_expiration = {
          noncurrent_days = 30
        }
        
        abort_incomplete_multipart_upload = {
          days_after_initiation = 7
        }
      }
    ]
  }

  tags = {
    Environment = var.environment
    Project     = var.project
    Terraform   = var.terraform
    Name        = var.static_files_bucket_name
    Purpose     = "Static-File-Storage"
  }

  depends_on = [aws_route53_zone.main_zone]
}

# S3 bucket policy - CloudFront-only access (security enhancement)
resource "aws_s3_bucket_policy" "static_files" {
  bucket = module.static_files_bucket.s3_bucket_id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "AllowCloudFrontServicePrincipal"
        Effect = "Allow"
        Principal = {
          Service = "cloudfront.amazonaws.com"
        }
        Action   = "s3:GetObject"
        Resource = "${module.static_files_bucket.s3_bucket_arn}/*"
        Condition = {
          StringEquals = {
            "AWS:SourceArn" = module.static_files_cdn.cloudfront_distribution_arn
          }
        }
      }
    ]
  })

  depends_on = [
    module.static_files_bucket,
    module.static_files_cdn
  ]
}


Step 7: S3-based CloudFront Distribution

Optimized distribution configuration for static file delivery with file-type specific caching strategies.

# cloudfront-s3.tf
module "static_files_cdn" {
  source = "terraform-aws-modules/cloudfront/aws"

  aliases = ["cdn.enterprise.example.com"]
  comment = "Enterprise Static Files CDN Distribution"
  
  enabled             = true
  is_ipv6_enabled     = true
  price_class         = "PriceClass_100"
  retain_on_delete    = false
  wait_for_deployment = false

  # Origin Access Control setup (modern approach, replaces OAI)
  create_origin_access_control = true
  origin_access_control = {
    s3_oac = {
      description      = "CloudFront access to S3 static files"
      origin_type      = "s3"
      signing_behavior = "always"
      signing_protocol = "sigv4"
    }
  }

  # S3 Origin configuration
  origin = {
    s3_static_files = {
      domain_name           = module.static_files_bucket.s3_bucket_bucket_regional_domain_name
      origin_access_control = "s3_oac"
    }
  }

  # Default cache behavior - long cache for static files
  default_cache_behavior = {
    target_origin_id       = "s3_static_files"
    viewer_protocol_policy = "redirect-to-https"
    allowed_methods        = ["GET", "HEAD", "OPTIONS"]
    cached_methods         = ["GET", "HEAD"]
    compress               = true

    # S3 doesn't require cookies or query strings
    use_forwarded_values = true
    query_string         = false
    cookies_forward      = "none"

    # Long TTL for static files
    min_ttl     = 0
    default_ttl = 86400    # 24 hours
    max_ttl     = 31536000 # 1 year
  }

  # File-type specific cache control
  ordered_cache_behavior = [
    # Image files - very long cache (low change frequency)
    {
      path_pattern           = "*.{jpg,jpeg,png,gif,webp,svg,ico}"
      target_origin_id       = "s3_static_files"
      viewer_protocol_policy = "https-only"
      allowed_methods        = ["GET", "HEAD"]
      cached_methods         = ["GET", "HEAD"]
      compress               = true

      use_forwarded_values = true
      query_string         = false
      cookies_forward      = "none"

      min_ttl     = 0
      default_ttl = 2592000  # 30 days
      max_ttl     = 31536000 # 1 year
    },
    
    # CSS/JS files - long cache (compression optimization)
    {
      path_pattern           = "*.{css,js}"
      target_origin_id       = "s3_static_files"
      viewer_protocol_policy = "https-only"
      allowed_methods        = ["GET", "HEAD"]
      cached_methods         = ["GET", "HEAD"]
      compress               = true

      use_forwarded_values = true
      query_string         = false
      cookies_forward      = "none"

      min_ttl     = 0
      default_ttl = 604800   # 7 days
      max_ttl     = 2592000  # 30 days
    },
    
    # Download files - long cache + CORS headers
    {
      path_pattern           = "/downloads/*"
      target_origin_id       = "s3_static_files"
      viewer_protocol_policy = "https-only"
      allowed_methods        = ["GET", "HEAD", "OPTIONS"]
      cached_methods         = ["GET", "HEAD"]
      compress               = true

      use_forwarded_values = true
      query_string         = true
      headers              = ["Origin", "Access-Control-Request-Headers", "Access-Control-Request-Method"]
      cookies_forward      = "none"

      min_ttl     = 0
      default_ttl = 86400    # 1 day
      max_ttl     = 31536000 # 1 year
    },
    
    # Document files - medium cache (compression disabled)
    {
      path_pattern           = "*.{pdf,doc,docx,xls,xlsx,ppt,pptx,zip,rar}"
      target_origin_id       = "s3_static_files"
      viewer_protocol_policy = "https-only"
      allowed_methods        = ["GET", "HEAD"]
      cached_methods         = ["GET", "HEAD"]
      compress               = false  # Pre-compressed files don't need additional compression

      use_forwarded_values = true
      query_string         = false
      cookies_forward      = "none"

      min_ttl     = 0
      default_ttl = 604800   # 7 days
      max_ttl     = 2592000  # 30 days
    }
  ]

  # SSL certificate configuration
  viewer_certificate = {
    acm_certificate_arn      = module.cloudfront_certificate.acm_certificate_arn
    ssl_support_method       = "sni-only"
    minimum_protocol_version = "TLSv1.2_2021"
  }

  # No geographic restrictions
  geo_restriction = {
    restriction_type = "none"
  }

  # Default index file
  default_root_object = "index.html"

  # Error page configuration
  custom_error_response = [
    {
      error_code         = 403
      response_code      = 404
      response_page_path = "/errors/404.html"
    },
    {
      error_code         = 404
      response_code      = 404
      response_page_path = "/errors/404.html"
    }
  ]

  tags = {
    Environment = var.environment
    Project     = var.project
    Terraform   = var.terraform
    Name        = "enterprise-static-files-cdn"
    Purpose     = "Static-File-Distribution"
  }

  depends_on = [
    module.static_files_bucket,
    module.cloudfront_certificate
  ]
}


Step 8: Advanced Security and Optimization


CloudFront Functions for Security Headers

# cloudfront-functions.tf
resource "aws_cloudfront_function" "security_headers" {
  name    = "add-security-headers"
  runtime = "cloudfront-js-1.0"
  comment = "Add security headers to all responses"
  publish = true

  code = <<-EOT
function handler(event) {
    var response = event.response;
    var headers = response.headers;

    // Security headers implementation
    headers['strict-transport-security'] = {
        value: 'max-age=31536000; includeSubdomains; preload'
    };
    headers['content-security-policy'] = {
        value: "default-src 'self'; img-src 'self' data: https:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
    };
    headers['x-frame-options'] = {value: 'DENY'};
    headers['x-content-type-options'] = {value: 'nosniff'};
    headers['referrer-policy'] = {value: 'strict-origin-when-cross-origin'};
    headers['permissions-policy'] = {
        value: 'geolocation=(), camera=(), microphone=()'
    };

    return response;
}
EOT
}


CI/CD IAM Role Configuration

# iam-deployment.tf
resource "aws_iam_role" "cicd_deployment_role" {
  name = "enterprise-cicd-deployment-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "codebuild.amazonaws.com"  # CodeBuild or required service
        }
      }
    ]
  })

  tags = {
    Environment = var.environment
    Purpose     = "CI-CD-Deployment"
  }
}

resource "aws_iam_role_policy" "s3_deployment_policy" {
  name = "s3-deployment-policy"
  role = aws_iam_role.cicd_deployment_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "s3:PutObject",
          "s3:PutObjectAcl",
          "s3:GetObject",
          "s3:DeleteObject",
          "s3:ListBucket"
        ]
        Resource = [
          module.static_files_bucket.s3_bucket_arn,
          "${module.static_files_bucket.s3_bucket_arn}/*"
        ]
      },
      {
        Effect = "Allow"
        Action = [
          "cloudfront:CreateInvalidation",
          "cloudfront:GetInvalidation",
          "cloudfront:ListInvalidations"
        ]
        Resource = [
          module.static_files_cdn.cloudfront_distribution_arn,
          module.api_cdn.cloudfront_distribution_arn
        ]
      }
    ]
  })
}


Step 9: WAF Integration for Enhanced Security

# waf-protection.tf
resource "aws_wafv2_web_acl" "cdn_protection" {
  name  = "enterprise-cdn-protection"
  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                = "CommonRuleSetMetric"
      sampled_requests_enabled   = true
    }
  }

  rule {
    name     = "AWSManagedRulesKnownBadInputsRuleSet"
    priority = 2

    override_action {
      none {}
    }

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

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

  rule {
    name     = "RateLimitRule"
    priority = 3

    action {
      block {}
    }

    statement {
      rate_based_statement {
        limit              = 2000
        aggregate_key_type = "IP"
      }
    }

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

  tags = {
    Environment = var.environment
    Name        = "enterprise-cdn-waf"
  }
}


Step 10: Monitoring and Alerting Configuration

# monitoring.tf
resource "aws_cloudwatch_metric_alarm" "high_4xx_error_rate" {
  alarm_name          = "cloudfront-high-4xx-error-rate"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = "2"
  metric_name         = "4xxErrorRate"
  namespace           = "AWS/CloudFront"
  period              = "300"
  statistic           = "Average"
  threshold           = "5.0"
  alarm_description   = "CloudFront 4xx error rate exceeds threshold"
  alarm_actions       = [aws_sns_topic.alerts.arn]

  dimensions = {
    DistributionId = module.api_cdn.cloudfront_distribution_id
  }

  tags = {
    Environment = var.environment
    Purpose     = "CDN-Monitoring"
  }
}

resource "aws_cloudwatch_metric_alarm" "high_5xx_error_rate" {
  alarm_name          = "cloudfront-high-5xx-error-rate"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = "2"
  metric_name         = "5xxErrorRate"
  namespace           = "AWS/CloudFront"
  period              = "300"
  statistic           = "Average"
  threshold           = "2.0"
  alarm_description   = "CloudFront 5xx error rate exceeds threshold"
  alarm_actions       = [aws_sns_topic.alerts.arn]

  dimensions = {
    DistributionId = module.api_cdn.cloudfront_distribution_id
  }

  tags = {
    Environment = var.environment
    Purpose     = "CDN-Monitoring"
  }
}

resource "aws_cloudwatch_metric_alarm" "low_cache_hit_rate" {
  alarm_name          = "cloudfront-low-cache-hit-rate"
  comparison_operator = "LessThanThreshold"
  evaluation_periods  = "3"
  metric_name         = "CacheHitRate"
  namespace           = "AWS/CloudFront"
  period              = "900"
  statistic           = "Average"
  threshold           = "80.0"
  alarm_description   = "CloudFront cache hit rate is below optimal threshold"
  alarm_actions       = [aws_sns_topic.alerts.arn]

  dimensions = {
    DistributionId = module.static_files_cdn.cloudfront_distribution_id
  }

  tags = {
    Environment = var.environment
    Purpose     = "CDN-Performance"
  }
}

resource "aws_sns_topic" "alerts" {
  name = "enterprise-cdn-alerts"

  tags = {
    Environment = var.environment
    Purpose     = "CDN-Alerting"
  }
}


Step 11: Deployment and Validation


Comprehensive Validation Script


Operational Considerations


Cache Strategy Optimization

Content Type Cache Duration Reasoning Monitoring Focus
Authentication APIs No cache (0s) Security and real-time validation Response time, error rates
User-specific Data No cache (0s) Privacy and data freshness Origin load, personalization accuracy
Configuration Data Medium (30min-1hr) Balance between freshness and performance Cache hit rate, update propagation
Product Listings Short (15-30min) Inventory changes require quick updates Business impact of stale data
Health Checks Very short (30s-5min) Rapid failure detection Monitoring system responsiveness
Static Images Very long (30+ days) Rarely change, bandwidth savings Storage costs vs performance
CSS/JS Files Long (7-30 days) Version-controlled deployments Cache invalidation effectiveness
Download Files Long (1 day-1 year) Large files, expensive to transfer Bandwidth costs, user experience


Performance Optimization Strategies

# Advanced cache policy configuration
resource "aws_cloudfront_cache_policy" "optimized_api" {
  name        = "enterprise-optimized-api-cache-policy"
  comment     = "Optimized cache policy for API responses"
  default_ttl = 3600
  max_ttl     = 86400
  min_ttl     = 0

  parameters_in_cache_key_and_forwarded_to_origin {
    query_strings_config {
      query_string_behavior = "whitelist"
      query_strings {
        items = ["page", "limit", "sort", "filter"]  # Only necessary query parameters
      }
    }

    headers_config {
      header_behavior = "whitelist"
      headers {
        items = ["Authorization", "Content-Type", "Accept-Language"]  # Essential headers only
      }
    }

    cookies_config {
      cookie_behavior = "none"  # APIs typically don't need cookies
    }

    enable_accept_encoding_gzip   = true
    enable_accept_encoding_brotli = true
  }
}

# Response headers policy for performance
resource "aws_cloudfront_response_headers_policy" "performance_security" {
  name    = "enterprise-performance-security-headers"
  comment = "Performance and security headers for CDN"

  cors_config {
    access_control_allow_credentials = false
    access_control_allow_headers {
      items = ["Authorization", "Content-Type", "X-Requested-With"]
    }
    access_control_allow_methods {
      items = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
    }
    access_control_allow_origins {
      items = ["https://enterprise.example.com", "https://*.enterprise.example.com"]
    }
    access_control_max_age_sec = 86400
    origin_override            = false
  }

  security_headers_config {
    strict_transport_security {
      access_control_max_age_sec = 31536000
      include_subdomains         = true
      preload                    = true
      override                   = false
    }

    content_type_options {
      override = false
    }

    frame_options {
      frame_option = "DENY"
      override     = false
    }

    referrer_policy {
      referrer_policy = "strict-origin-when-cross-origin"
      override        = false
    }
  }

  custom_headers_config {
    items {
      header   = "X-CDN-Cache-Status"
      value    = "Enterprise-CDN"
      override = false
    }
  }
}


Cost Optimization Techniques

graph TD subgraph "Cost Optimization Strategies" A[Price Class Selection] --> A1[PriceClass_100: North America, Europe] A --> A2[PriceClass_200: + Asia, Africa] A --> A3[PriceClass_All: Global Coverage] B[Origin Shield] --> B1[Reduce Origin Requests] B --> B2[Improve Cache Hit Ratio] B --> B3[Lower Data Transfer Costs] C[Compression] --> C1[Enable Gzip/Brotli] C --> C2[Reduce Bandwidth Usage] C --> C3[Faster Content Delivery] D[Cache Optimization] --> D1[Longer TTL for Static Content] D --> D2[Appropriate TTL for Dynamic Content] D --> D3[Minimize Origin Requests] E[Request Routing] --> E1[Geographic Restrictions] E --> E2[Conditional Origins] E --> E3[Path-based Optimization] end


Disaster Recovery and Incident Response


Security Best Practices


Advanced WAF Rules

# Geo-blocking for security
resource "aws_wafv2_web_acl" "enhanced_protection" {
  name  = "enterprise-enhanced-cdn-protection"
  scope = "CLOUDFRONT"

  default_action {
    allow {}
  }

  # Geographic restrictions
  rule {
    name     = "GeoBlocking"
    priority = 1

    action {
      block {}
    }

    statement {
      geo_match_statement {
        country_codes = ["CN", "RU", "KP"]  # Block specific countries
      }
    }

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

  # IP reputation blocking
  rule {
    name     = "AWSManagedRulesAmazonIpReputationList"
    priority = 2

    override_action {
      none {}
    }

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

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

  # SQL injection protection
  rule {
    name     = "AWSManagedRulesSQLiRuleSet"
    priority = 3

    override_action {
      none {}
    }

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

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


Conclusion

This comprehensive CDN implementation guide demonstrates how to build enterprise-grade content delivery infrastructure using Kubernetes and AWS CloudFront. The dual distribution strategy addresses both dynamic API content and static file delivery requirements through specialized optimization approaches.


Key architectural achievements include:

  1. Intelligent Caching Strategy: Content-aware TTL configurations that balance performance with data freshness requirements
  2. Zero-Trust Security Model: Origin Access Control (OAC) implementation ensuring S3 buckets remain completely private while enabling CloudFront access
  3. Cost-Effective Operations: Strategic use of Price Classes, Origin Shield, and compression to optimize global delivery costs
  4. Proactive Monitoring: Comprehensive CloudWatch metrics and alerting for maintaining optimal performance

The modern OAC approach represents a significant security improvement over legacy OAI methods, providing more granular access control and better integration with AWS IAM policies. Additionally, the IPv6 support ensures future-proof connectivity for mobile and international users.


Operational excellence is achieved through:


For production deployments, continuous performance monitoring and cache hit rate analysis are essential for optimization. Regular security reviews and adoption of new AWS features will ensure the CDN infrastructure remains efficient and secure as business requirements evolve.

The implementation provides a solid foundation for scaling global applications while maintaining security, performance, and cost efficiency across diverse content delivery scenarios.



References