Skip to content

Latest commit

 

History

History
426 lines (386 loc) · 31 KB

README.md

File metadata and controls

426 lines (386 loc) · 31 KB

Azure CDN FrontDoor

Changelog Notice Apache V2 License OpenTofu Registry

This Terraform module is designed to create an Azure CDN FrontDoor (Standard/Premium) resource.

Global versioning rule for Claranet Azure modules

Module version Terraform version OpenTofu version AzureRM version
>= 8.x.x Unverified 1.8.x >= 4.0
>= 7.x.x 1.3.x >= 3.0
>= 6.x.x 1.x >= 3.0
>= 5.x.x 0.15.x >= 2.0
>= 4.x.x 0.13.x / 0.14.x >= 2.0
>= 3.x.x 0.12.x >= 2.0
>= 2.x.x 0.12.x < 2.0
< 2.x.x 0.11.x < 2.0

Contributing

If you want to contribute to this repository, feel free to use our pre-commit git hook configuration which will help you automatically update and format some files for you by enforcing our Terraform code module best-practices.

More details are available in the CONTRIBUTING.md file.

Usage

This module is optimized to work with the Claranet terraform-wrapper tool which set some terraform variables in the environment needed by this module. More details about variables set by the terraform-wrapper available in the documentation.

⚠️ Since modules version v8.0.0, we do not maintain/check anymore the compatibility with Hashicorp Terraform. Instead, we recommend to use OpenTofu.

# NOTE: In order for the certificate to be used by Azure FrontDoor, it must be PKCS#12 PFX 3DES.
# The PFX must only contain the leaf and any intermediates, but it must not contain any Root CAs
# already trusted by Azure. openssl v3 requires -legacy flag for 3DES compatibility.
# Generate the CSR, get it signed by the CA, then create the PFX.
#
# openssl pkcs12 -export -out cert.pfx -inkey leaf.key -in leaf.pem -certfile intermediate.pem -legacy
#
resource "azurerm_key_vault_certificate" "cert" {
  name         = "custom-contoso-com"
  key_vault_id = var.key_vault_id

  certificate {
    contents = "abcd" # filebase64("./cert.pfx")
    password = ""
  }

  # The following is required for PFX imports, but not PEM.
  certificate_policy {
    issuer_parameters {
      name = "Unknown"
    }
    key_properties {
      exportable = true
      key_size   = 2048
      key_type   = "RSA"
      reuse_key  = false
    }
    secret_properties {
      content_type = "application/x-pkcs12"
    }
  }

}

module "cdn_frontdoor" {
  source  = "claranet/cdn-frontdoor/azurerm"
  version = "x.x.x"

  client_name         = var.client_name
  environment         = var.environment
  stack               = var.stack
  resource_group_name = module.rg.name

  sku_name = "Premium_AzureFrontDoor"

  logs_destinations_ids = [
    module.logs.id,
    module.logs.storage_account_id,
  ]

  endpoints = [
    {
      name = "web"
    },
    {
      name    = "azure"
      enabled = false
    },
  ]

  origin_groups = [
    {
      name = "contoso"
      health_probe = {
        interval_in_seconds = 250
        path                = "/"
        protocol            = "Https"
        request_type        = "GET"
      }
      load_balancing = {
        successful_samples_required = 1
      }
    },
    {
      name = "contoso2"
      health_probe = {
        interval_in_seconds = 250
        path                = "/"
        protocol            = "Https"
        request_type        = "GET"
      }
    },
  ]

  origins = [
    {
      name                           = "web"
      origin_group_name              = "contoso"
      certificate_name_check_enabled = false
      host_name                      = "www.contoso.com"
    },
    {
      name                           = "azure"
      origin_group_name              = "contoso2"
      certificate_name_check_enabled = false
      host_name                      = "azure.contoso.com"
    },
  ]

  custom_domains = [
    {
      name      = "www"
      host_name = "www.contoso.com"
    },
    {
      name      = "custom-contoso-com"
      host_name = "custom.contoso.com"
      tls = {
        certificate_type         = "CustomerCertificate"
        key_vault_certificate_id = azurerm_key_vault_certificate.cert.id
      }
    }
  ]

  routes = [
    {
      name                 = "route66"
      endpoint_name        = "web"
      origin_group_name    = "contoso"
      origins_names        = ["web", "azure"]
      forwarding_protocol  = "HttpsOnly"
      patterns_to_match    = ["/*"]
      supported_protocols  = ["Http", "Https"]
      custom_domains_names = ["www"]
      rule_sets_names      = ["my_rule_set", "my_rule_set2"]
    },
    {
      name                = "route2"
      endpoint_name       = "azure"
      origin_group_name   = "contoso2"
      origins_names       = ["web"]
      forwarding_protocol = "HttpsOnly"
      patterns_to_match   = ["/contoso"]
      supported_protocols = ["Http", "Https"]
      rule_sets_names     = ["my_rule_set", "my_rule_set2"]
    },
  ]

  rule_sets = [
    {
      name                 = "my_rule_set"
      custom_resource_name = "custom_rule"

      rules = [{
        name                 = "redirect"
        custom_resource_name = "myrulename"
        order                = 1
        actions = {
          response_header_actions = [
            {
              header_action = "Overwrite"
              header_name   = "Access-Control-Allow-Origin"
              value         = "https://www.foo.bar.fr"
            },
            {
              header_action = "Overwrite"
              header_name   = "Access-Control-Allow-Credentials"
              value         = "true"
            },
            {
              header_action = "Overwrite"
              header_name   = "Access-Control-Allow-Headers"
              value         = "Authorization, Content-Type, ocp-apim-subscription-key"
            },
            {
              header_action = "Overwrite"
              header_name   = "Access-Control-Allow-Methods"
              value         = "POST,PUT,GET,DELETE,OPTIONS"
            },
          ]
          url_rewrite_actions = [{
            source_pattern = "/"
            destination    = "/contoso"
          }]
        }
        conditions = {
          is_device_conditions = [{
            operator     = "Equal"
            match_values = ["Desktop"]
          }]
        }
      }]
    },
    {
      name                 = "my_rule_set2"
      custom_resource_name = "custom_rule2"
    },
  ]

  firewall_policies = [{
    name                              = "test"
    enabled                           = true
    mode                              = "Prevention"
    redirect_url                      = "https://www.contoso.com"
    custom_block_response_status_code = 403
    custom_block_response_body        = "PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg=="

    custom_rules = [
      {
        name                           = "Rule1"
        enabled                        = true
        priority                       = 1
        rate_limit_duration_in_minutes = 1
        rate_limit_threshold           = 10
        type                           = "MatchRule"
        action                         = "Block"
        match_conditions = [{
          match_variable     = "RemoteAddr"
          operator           = "IPMatch"
          negation_condition = false
          match_values       = ["10.0.1.0/24", "10.0.0.0/24"]
        }]
      },
      {
        name                           = "Rule2"
        enabled                        = true
        priority                       = 2
        rate_limit_duration_in_minutes = 1
        rate_limit_threshold           = 10
        type                           = "MatchRule"
        action                         = "Block"
        match_conditions = [
          {
            match_variable     = "RemoteAddr"
            operator           = "IPMatch"
            negation_condition = false
            match_values       = ["192.168.1.0/24"]
          },
          {
            match_variable     = "RequestHeader"
            selector           = "UserAgent"
            operator           = "Contains"
            negation_condition = false
            match_values       = ["windows"]
            transforms         = ["Lowercase", "Trim"]
          },
        ]
      },
    ]

    managed_rules = [
      {
        type    = "DefaultRuleSet"
        version = "1.0"
        action  = "Log"
        exclusions = [{
          match_variable = "QueryStringArgNames"
          operator       = "Equals"
          selector       = "not_suspicious"
        }]
        overrides = [
          {
            rule_group_name = "PHP"
            rules = [{
              rule_id = "933100"
              enabled = false
              action  = "Block"
            }]
          },
          {
            rule_group_name = "SQLI"
            exclusions = [{
              match_variable = "QueryStringArgNames"
              operator       = "Equals"
              selector       = "really_not_suspicious"
            }]
            rules = [{
              rule_id = "942200"
              action  = "Block"
              exclusions = [{
                match_variable = "QueryStringArgNames"
                operator       = "Equals"
                selector       = "innocent"
              }]
            }]
          },
        ]
      },
      {
        type    = "Microsoft_BotManagerRuleSet"
        version = "1.0"
        action  = "Log"
      },
    ]
  }]

  security_policies = [{
    name                 = "MySecurityPolicy"
    custom_resource_name = "MyBetterNamedSecurityPolicy"
    firewall_policy_name = "test"
    patterns_to_match    = ["/*"]
    custom_domain_names  = ["www"]
    endpoint_names       = ["web", "azure"]
  }]

  extra_tags = {
    foo = "bar"
  }
}

Providers

Name Version
azurecaf ~> 1.2.28
azurerm ~> 4.0

Modules

Name Source Version
diagnostics claranet/diagnostic-settings/azurerm ~> 8.0.0

Resources

Name Type
azurerm_cdn_frontdoor_custom_domain.main resource
azurerm_cdn_frontdoor_endpoint.main resource
azurerm_cdn_frontdoor_firewall_policy.main resource
azurerm_cdn_frontdoor_origin.main resource
azurerm_cdn_frontdoor_origin_group.main resource
azurerm_cdn_frontdoor_profile.main resource
azurerm_cdn_frontdoor_route.main resource
azurerm_cdn_frontdoor_rule.main resource
azurerm_cdn_frontdoor_rule_set.main resource
azurerm_cdn_frontdoor_secret.main resource
azurerm_cdn_frontdoor_security_policy.main resource
azurecaf_name.cdn_frontdoor_custom_domain data source
azurecaf_name.cdn_frontdoor_endpoint data source
azurecaf_name.cdn_frontdoor_firewall_policy data source
azurecaf_name.cdn_frontdoor_origin data source
azurecaf_name.cdn_frontdoor_origin_group data source
azurecaf_name.cdn_frontdoor_profile data source
azurecaf_name.cdn_frontdoor_route data source
azurecaf_name.cdn_frontdoor_rule data source
azurecaf_name.cdn_frontdoor_rule_set data source
azurecaf_name.cdn_frontdoor_security_policy data source

Inputs

Name Description Type Default Required
client_name Client name/account used in naming. string n/a yes
custom_domains Azure CDN FrontDoor custom domains configurations.
list(object({
name = string
custom_resource_name = optional(string)
host_name = string
dns_zone_id = optional(string)
tls = optional(object({
certificate_type = optional(string, "ManagedCertificate")
minimum_tls_version = optional(string, "TLS12")
cdn_frontdoor_secret_id = optional(string)
key_vault_certificate_id = optional(string)
}), {})
}))
[] no
custom_name Specifies the name of the FrontDoor Profile. string "" no
default_tags_enabled Option to enable or disable default tags. bool true no
diagnostic_settings_custom_name Custom name of the diagnostics settings, name will be 'default' if not set. string "default" no
endpoints Azure CDN FrontDoor endpoints configurations.
list(object({
name = string
prefix = optional(string)
custom_resource_name = optional(string)
enabled = optional(bool, true)
}))
[] no
environment Project environment. string n/a yes
extra_tags Extra tags to add. map(string) {} no
firewall_policies Azure CDN Frontdoor firewall policies configurations.
list(object({
name = string
custom_resource_name = optional(string)
enabled = optional(bool, true)
mode = optional(string, "Prevention")
redirect_url = optional(string)
custom_block_response_status_code = optional(number)
custom_block_response_body = optional(string)
custom_rules = optional(list(object({
name = string
action = string
enabled = optional(bool, true)
priority = number
type = string
rate_limit_duration_in_minutes = optional(number, 1)
rate_limit_threshold = optional(number, 10)
match_conditions = list(object({
match_variable = string
match_values = list(string)
operator = string
selector = optional(string)
negate_condition = optional(bool)
transforms = optional(list(string), [])
}))
})), [])
managed_rules = optional(list(object({
type = string
version = optional(string, "1.0")
action = string
exclusions = optional(list(object({
match_variable = string
operator = string
selector = string
})), [])
overrides = optional(list(object({
rule_group_name = string
exclusions = optional(list(object({
match_variable = string
operator = string
selector = string
})), [])
rules = optional(list(object({
rule_id = string
action = string
enabled = optional(bool, true)
exclusions = optional(list(object({
match_variable = string
operator = string
selector = string
})), []) })), [])
})), [])
})), [])
}))
[] no
logs_categories Log categories to send to destinations. list(string) null no
logs_destinations_ids List of destination resources IDs for logs diagnostic destination.
Can be Storage Account, Log Analytics Workspace and Event Hub. No more than one of each can be set.
If you want to use Azure EventHub as a destination, you must provide a formatted string containing both the EventHub Namespace authorization send ID and the EventHub name (name of the queue to use in the Namespace) separated by the | character.
list(string) n/a yes
logs_metrics_categories Metrics categories to send to destinations. list(string) null no
name_prefix Optional prefix for the generated name string "" no
name_suffix Optional suffix for the generated name string "" no
origin_groups Azure CDN FrontDoor origin groups configurations.
list(object({
name = string
custom_resource_name = optional(string)
session_affinity_enabled = optional(bool, true)
restore_traffic_time_to_healed_or_new_endpoint_in_minutes = optional(number, 10)
health_probe = optional(object({
interval_in_seconds = number
path = string
protocol = string
request_type = string
}))
load_balancing = optional(object({
additional_latency_in_milliseconds = optional(number, 50)
sample_size = optional(number, 4)
successful_samples_required = optional(number, 3)
}), {})
}))
[] no
origins Azure CDN FrontDoor origins configurations.
list(object({
name = string
custom_resource_name = optional(string)
origin_group_name = string
enabled = optional(bool, true)
certificate_name_check_enabled = optional(bool, true)

host_name = string
http_port = optional(number, 80)
https_port = optional(number, 443)
origin_host_header = optional(string)
priority = optional(number, 1)
weight = optional(number, 1)

private_link = optional(object({
request_message = optional(string)
target_type = optional(string)
location = string
private_link_target_id = string
}))
}))
[] no
resource_group_name Resource group name. string n/a yes
response_timeout_seconds Specifies the maximum response timeout in seconds. Possible values are between 16 and 240 seconds (inclusive). number 120 no
routes Azure CDN FrontDoor routes configurations.
list(object({
name = string
custom_resource_name = optional(string)
enabled = optional(bool, true)

endpoint_name = string
origin_group_name = string
origins_names = list(string)

forwarding_protocol = optional(string, "HttpsOnly")
patterns_to_match = optional(list(string), ["/*"])
supported_protocols = optional(list(string), ["Http", "Https"])
cache = optional(object({
query_string_caching_behavior = optional(string, "IgnoreQueryString")
query_strings = optional(list(string))
compression_enabled = optional(bool, false)
content_types_to_compress = optional(list(string))
}))

custom_domains_names = optional(list(string), [])
origin_path = optional(string, "/")
rule_sets_names = optional(list(string), [])

https_redirect_enabled = optional(bool, true)
link_to_default_domain = optional(bool, true)
}))
[] no
rule_sets Azure CDN FrontDoor rule sets and associated rules configurations.
list(object({
name = string
custom_resource_name = optional(string)
rules = optional(list(object({
name = string
custom_resource_name = optional(string)
order = number
behavior_on_match = optional(string, "Continue")

actions = object({
url_rewrite_actions = optional(list(object({
source_pattern = optional(string)
destination = optional(string)
preserve_unmatched_path = optional(bool, false)
})), [])
url_redirect_actions = optional(list(object({
redirect_type = string
destination_hostname = string
redirect_protocol = optional(string, "MatchRequest")
destination_path = optional(string, "")
query_string = optional(string, "")
destination_fragment = optional(string, "")
})), [])
route_configuration_override_actions = optional(list(object({
cache_duration = optional(string, "1.12:00:00")
cdn_frontdoor_origin_group_id = optional(string)
forwarding_protocol = optional(string, "MatchRequest")
query_string_caching_behavior = optional(string, "IgnoreQueryString")
query_string_parameters = optional(list(string))
compression_enabled = optional(bool, false)
cache_behavior = optional(string, "HonorOrigin")
})), [])
request_header_actions = optional(list(object({
header_action = string
header_name = string
value = optional(string)
})), [])
response_header_actions = optional(list(object({
header_action = string
header_name = string
value = optional(string)
})), [])
})

conditions = optional(object({
remote_address_conditions = optional(list(object({
operator = string
negate_condition = optional(bool, false)
match_values = optional(list(string))
})), [])
request_method_conditions = optional(list(object({
match_values = list(string)
operator = optional(string, "Equal")
negate_condition = optional(bool, false)
})), [])
query_string_conditions = optional(list(object({
operator = string
negate_condition = optional(bool, false)
match_values = optional(list(string))
transforms = optional(list(string), ["Lowercase"])
})), [])
post_args_conditions = optional(list(object({
post_args_name = string
operator = string
negate_condition = optional(bool, false)
match_values = optional(list(string))
transforms = optional(list(string), ["Lowercase"])
})), [])
request_uri_conditions = optional(list(object({
operator = string
negate_condition = optional(bool, false)
match_values = optional(list(string))
transforms = optional(list(string), ["Lowercase"])
})), [])
request_header_conditions = optional(list(object({
header_name = string
operator = string
negate_condition = optional(bool, false)
match_values = optional(list(string))
transforms = optional(list(string), ["Lowercase"])
})), [])
request_body_conditions = optional(list(object({
operator = string
match_values = list(string)
negate_condition = optional(bool, false)
transforms = optional(list(string), ["Lowercase"])
})), [])
request_scheme_conditions = optional(list(object({
operator = optional(string, "Equal")
negate_condition = optional(bool, false)
match_values = optional(string, "HTTP")
})), [])
url_path_conditions = optional(list(object({
operator = string
negate_condition = optional(bool, false)
match_values = optional(list(string))
transforms = optional(list(string), ["Lowercase"])
})), [])
url_file_extension_conditions = optional(list(object({
operator = string
negate_condition = optional(bool, false)
match_values = list(string)
transforms = optional(list(string), ["Lowercase"])
})), [])
url_filename_conditions = optional(list(object({
operator = string
match_values = list(string)
negate_condition = optional(bool, false)
transforms = optional(list(string), ["Lowercase"])
})), [])
http_version_conditions = optional(list(object({
match_values = list(string)
operator = optional(string, "Equal")
negate_condition = optional(bool, false)
})), [])
cookies_conditions = optional(list(object({
cookie_name = string
operator = string
negate_condition = optional(bool, false)
match_values = optional(list(string))
transforms = optional(list(string), ["Lowercase"])
})), [])
is_device_conditions = optional(list(object({
operator = optional(string, "Equal")
negate_condition = optional(bool, false)
match_values = optional(list(string), ["Mobile"])
})), [])
socket_address_conditions = optional(list(object({
operator = string
negate_condition = optional(bool, false)
match_values = optional(list(string))
})), [])
client_port_conditions = optional(list(object({
operator = string
negate_condition = optional(bool, false)
match_values = optional(list(string))
})), [])
server_port_conditions = optional(list(object({
operator = string
match_values = list(string)
negate_condition = optional(bool, false)
})), [])
host_name_conditions = optional(list(object({
operator = string
match_values = optional(list(string))
transforms = optional(list(string), ["Lowercase"])
})), [])
ssl_protocol_conditions = optional(list(object({
match_values = list(string)
operator = optional(string, "Equal")
negate_condition = optional(bool, false)
})), [])
}), null)
})), [])
}))
[] no
security_policies Azure CDN FrontDoor security policies configurations.
list(object({
name = string
custom_resource_name = optional(string)
firewall_policy_name = string
patterns_to_match = optional(list(string), ["/*"])
custom_domain_names = optional(list(string), [])
endpoint_names = optional(list(string), [])
}))
[] no
sku_name Specifies the SKU for this Azure CDN FrontDoor profile. Possible values include Standard_AzureFrontDoor and Premium_AzureFrontDoor. string "Standard_AzureFrontDoor" no
stack Project stack name. string n/a yes

Outputs

Name Description
id The ID of the CDN FrontDoor Profile.
module_diagnostics Diagnostics Settings module output.
name The name of the CDN FrontDoor Profile.
resource Azure CDN FrontDoor Profile output object.
resource_custom_domain Azure CDN FrontDoor custom domain resource output.
resource_endpoint Azure CDN FrontDoor endpoints resource output.
resource_firewall_policy Azure CDN FrontDoor firewall policy resource output.
resource_origin Azure CDN FrontDoor origin resource output.
resource_origin_group Azure CDN FrontDoor origin group resource output.
resource_route Azure CDN FrontDoor route resource output.
resource_rule Azure CDN FrontDoor rule resource output.
resource_rule_set Azure CDN FrontDoor rule set resource output.
resource_secret Azure CDN FrontDoor secret resource output.
resource_security_policy Azure CDN FrontDoor security policy resource output.

Related documentation

Azure Front Door REST API: docs.microsoft.com/en-us/rest/api/frontdoor/