Panfactum LogoPanfactum
Infrastructure ModulesSubmodulesKuberneteskube_aws_cdn
kube_aws_cdn
Beta
Submodule
Source Code Link

AWS CDN for Kubernetes Ingresses

This module creates a CDN for a set of Kubernetes Ingresses by aggregating the cdn_origin_configs output from instances of the kube_ingress module and forwarding them to the aws_cdn module.

This module takes the same arguments as aws_cdn, so see it's module documentation for more information.

Limitations

  • The upstream ingresses for this module must all use the same set of domains. AWS Cloudfront provides no ability to perform routing based on domain names (only HTTP paths). If the ingresses you provide this module use different sets of domains, your routing will break in unexpected ways.

  • Changing the domains of your upstream ingresses will cause the Cloudfront distribution to re-provision its certificates causing a brief window of downtime (1-2 minutes).

  • You cannot use the same domain name on multiple CDNs. As a result, you can only create ONE kube_aws_cdn resource for all ingresses that use a particular domain name.

  • For additional limitations, see the aws_cdn module docs.

Usage

terraform {
   required_providers {
      ...
      aws = {
         source                = "hashicorp/aws"
         version               = "5.70.0"
         configuration_aliases = [aws.global]
      }
      ...
   }
}

module "ingress_1" {
   source = "${var.pf_module_source}kube_ingress${var.pf_module_ref}"

   namespace    = local.namespace
   name         = "example1"
   domains      = ["example.com"]
   
    ...
   
   # CDN mode MUST be enabled if you want to use a
   # CDN in front of an ingress
   cdn_mode_enabled = true
}

module "ingress_2" {
   source = "../kube_ingress"

   namespace    = local.namespace
   name         = "example2"
   domains      = ["example.com"]

   ...
   
   cdn_mode_enabled = true
   ingress_configs  = [{
      path_prefix = "/test"
      
      ...
      
      # You can configure CDN behavior on a per-ingress basis
      # See the kube_ingress documentation for more information
      cdn = {
         default_cache_behavior = {
            headers_in_cache_key = ["Authorization"]
         }
      }
   }]

}

module "cdn" {
   source = "${var.pf_module_source}kube_aws_cdn${var.pf_module_ref}"
   
   # Since the CDN operates globally, you must use the global
   # provider as follows:
   providers = {
     aws.global = aws.global
   }

   name               = "example"
   
   # Concatenate the CDN configs provided by each
   # ingress module and pass them to the CDN module
   origin_configs = concat(
     module.ingress_1.cdn_origin_configs,
     module.ingress_2.cdn_origin_configs
   )
}

Providers

The following providers are needed by this module:

  • archive (2.6.0)

  • aws (5.70.0)

  • pf (0.0.3)

  • random (3.6.0)

Required Inputs

The following input variables are required:

name

Description: The name of the CDN that will get created

Type: string

origin_configs

Description: A list of configuration settings for communicating with the upstream ingress resources. Do NOT set this manually. Use the outputs from kube_ingress.

Type:

list(object({
    origin_id            = optional(string)          # A globally unique identifier for this origin (will be automatically computed if not provided)
    origin_domain        = string                    # The domain name of the ingress origin
    domains              = list(string)              # The domains for this ingress
    path_prefix          = optional(string, "/")     # Only traffic with this HTTP path prefix will be routed to the indicated origin
    extra_origin_headers = optional(map(string), {}) # Headers sent from the CDN to the origin

    # The default behavior of the CDN before routing requests to this ingress
    default_cache_behavior = optional(object({
      caching_enabled      = optional(bool, true)                                                                 # Whether the CDN should cache responses from the origin (overrides all other caching settings)
      allowed_methods      = optional(list(string), ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]) # What HTTP methods are allowed
      cached_methods       = optional(list(string), ["GET", "HEAD"])                                              # What HTTP methods will be cached
      min_ttl              = optional(number, 0)                                                                  # Minimum cache time
      default_ttl          = optional(number, 86400)                                                              # Default cache time
      max_ttl              = optional(number, 31536000)                                                           # Maximum cache time
      cookies_in_cache_key = optional(list(string), ["*"])                                                        # Which cookies will be included in the cache key (Providing "*" means ALL cookies)
      headers_in_cache_key = optional(list(string), [                                                             # Which headers will be included in the cache key
        "Authorization",
        "Origin",
        "x-http-method-override",
        "x-http-method",
        "x-method-override",
        "x-forwarded-host",
        "x-host",
        "x-original-url",
        "x-rewrite-url",
        "forwarded"
      ])
      query_strings_in_cache_key  = optional(list(string), ["*"])         # Which query strings will be included in the cache key (Providing "*" means ALL query strings)
      cookies_not_forwarded       = optional(list(string), [])            # Which cookies will NOT be forwarded to the ingress from the CDN
      headers_not_forwarded       = optional(list(string), [])            # Which headers will NOT be forwarded to the ingress from CDN
      query_strings_not_forwarded = optional(list(string), [])            # Which query strings will NOT be forwarded to the ingress from the CDN
      compression_enabled         = optional(bool, true)                  # Whether the CDN performs compression on your assets
      viewer_protocol_policy      = optional(string, "redirect-to-https") # What should happen based on the client protocol (HTTP vs HTTPS)
    }))

    # Similar to default_cache_behavior but allows you to specific specific rules for certain path patterns
    # The keys for this map are the path patterns (e.g., "*.jpg")
    # Path patterns will automatically be prefixed with the path_prefix value, so it can be omitted
    path_match_behavior = optional(map(object({
      caching_enabled      = optional(bool, true) # Whether the CDN should cache responses from the origin (overrides all other caching settings)
      allowed_methods      = optional(list(string), ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"])
      cached_methods       = optional(list(string), ["GET", "HEAD"])
      min_ttl              = optional(number, 0)
      default_ttl          = optional(number, 86400)
      max_ttl              = optional(number, 31536000)
      cookies_in_cache_key = optional(list(string), ["*"])
      headers_in_cache_key = optional(list(string), [
        "Authorization",
        "Origin",
        "x-http-method-override",
        "x-http-method",
        "x-method-override",
        "x-forwarded-host",
        "x-host",
        "x-original-url",
        "x-rewrite-url",
        "forwarded"
      ])
      query_strings_in_cache_key  = optional(list(string), ["*"])
      cookies_not_forwarded       = optional(list(string), [])
      headers_not_forwarded       = optional(list(string), [])
      query_strings_not_forwarded = optional(list(string), [])
      compression_enabled         = optional(bool, true)
      viewer_protocol_policy      = optional(string, "redirect-to-https")
    })), {})
  }))

Optional Inputs

The following input variables are optional (have default values):

cors_additional_allowed_origins

Description: Specifies which origins are allowed besides the domain name specified. Use '*' to allow any origin.

Type: list(string)

Default: []

cors_allowed_headers

Description: Specifies which headers are allowed for CORS requests.

Type: list(string)

Default:

[
  "Content-Length"
]

cors_allowed_methods

Description: Specifies which methods are allowed. Can be GET, PUT, POST, DELETE or HEAD.

Type: list(string)

Default:

[
  "GET",
  "HEAD"
]

cors_enabled

Description: True if the CloudFront distribution should handle adding CORS headers instead of the origin.

Type: bool

Default: false

cors_max_age_seconds

Description: Time in seconds that the browser can cache the response for a preflight CORS request.

Type: number

Default: 3600

description

Description: A description for this CDN

Type: string

Default: null

geo_restriction_list

Description: A list of ISO 3166 country codes for the geographic restriction list (works for both whitelist and blacklist)

Type: list(string)

Default: []

geo_restriction_type

Description: What type of geographic restrictions to you want to apply to CDN clients

Type: string

Default: "none"

logging_cookies_enabled

Description: Whether cookies should be included in the request logs

Type: bool

Default: false

logging_enabled

Description: Whether request logging should be enabled for the CloudFront distribution

Type: bool

Default: false

logging_expire_after_days

Description: The number of days after which logs will be deleted. (0 to disable)

Type: number

Default: 0

origin_shield_enabled

Description: Whether origin shield should be enabled for the CloudFront distribution

Type: bool

Default: false

price_class

Description: The price class for the CDN

Type: string

Default: "PriceClass_100"

redirect_rules

Description: A list of redirect rules that the ingress will match against before sending requests to the upstreams

Type:

list(object({
    source    = string                # A regex string for matching the entire request url (^https://domain.com(/.*)?$)
    target    = string                # The redirect target (can use numbered capture groups from the source - https://domain2.com/$1)
    permanent = optional(bool, false) # If true will issue a 301 redirect; otherwise, will use 302
  }))

Default: []

Outputs

The following outputs are exported:

distribution_id

Description: The ID of the CloudFront distribution

logging_bucket_name

Description: The name of the log bucket for CloudFront access logs

Maintainer Notes

No notes.