Skip to content

Commit

Permalink
feat: (IAC-276) Support Azure Application Gateway with Azure WAF
Browse files Browse the repository at this point in the history
  • Loading branch information
riragh committed Mar 21, 2024
1 parent f12ea54 commit 020ffe9
Show file tree
Hide file tree
Showing 8 changed files with 398 additions and 1 deletion.
1 change: 1 addition & 0 deletions iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ resource "azurerm_user_assigned_identity" "uai" {
name = "${var.prefix}-aks-identity"
resource_group_name = local.aks_rg.name
location = var.location
tags = var.tags
}
7 changes: 6 additions & 1 deletion locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ locals {
cluster_endpoint_public_access_cidrs = var.cluster_api_mode == "private" ? [] : (var.cluster_endpoint_public_access_cidrs == null ? local.default_public_access_cidrs : var.cluster_endpoint_public_access_cidrs)
postgres_public_access_cidrs = var.postgres_public_access_cidrs == null ? local.default_public_access_cidrs : var.postgres_public_access_cidrs

subnets = { for k, v in var.subnets : k => v if !(k == "netapp" && var.storage_type == "standard") }
subnets = { for k, v in var.subnets : k => v if !(k == "netapp" && var.storage_type == "standard") && !(k == "gateway" && !var.create_app_gateway) }

# Kubernetes
kubeconfig_filename = "${var.prefix}-aks-kubeconfig.conf"
Expand All @@ -39,6 +39,11 @@ locals {
}
} : {}

# App Gateway
app_gateway_config = merge(var.app_gateway_defaults, var.app_gateway_config)
waf_policy_config = var.waf_policy != null ? jsondecode(file(var.waf_policy)) : null
waf_policy_enabled = local.waf_policy_config != null ? length(local.waf_policy_config) != 0 ? true : false : false

# Container Registry
container_registry_sku = title(var.container_registry_sku)

Expand Down
24 changes: 24 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,30 @@ module "message_broker" {
tags = var.tags
}

module "app_gateway" {
source = "./modules/azurerm_app_gateway"
count = var.create_app_gateway ? 1 : 0

prefix = var.prefix
resource_group_name = local.aks_rg.name
location = var.location
sku = local.app_gateway_config.sku
port = local.app_gateway_config.port
protocol = local.app_gateway_config.protocol
waf_policy_enabled = local.waf_policy_enabled
waf_policy_config = local.waf_policy_config
backend_host_name = local.app_gateway_config.backend_host_name
backend_trusted_root_certificate = local.app_gateway_config.backend_trusted_root_certificate
ssl_certificate = local.app_gateway_config.ssl_certificate
identity_ids = local.app_gateway_config.identity_ids
backend_address_pool_fqdn = local.app_gateway_config.backend_address_pool_fqdn
probe = local.app_gateway_config.probe
subnet_id = module.vnet.subnets["gateway"].id
tags = var.tags

depends_on = [module.vnet]
}

data "external" "git_hash" {
program = ["files/tools/iac_git_info.sh"]
}
Expand Down
216 changes: 216 additions & 0 deletions modules/azurerm_app_gateway/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Copyright © 2020-2023, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

## https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/application_gateway
## https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/web_application_firewall_policy

locals {
backend_address_pool_name = "${var.prefix}-backend-pool"
frontend_port_name = "${var.prefix}-frontend-port"
frontend_ip_configuration_name = "${var.prefix}-frontend-ip"
http_setting_name = "${var.prefix}-backend-setting"
listener_name = "${var.prefix}-listener"
request_routing_rule_name = "${var.prefix}-routing-rule"
}

resource "azurerm_public_ip" "gateway_ip" {
name = "${var.prefix}-gateway-public_ip"
location = var.location
resource_group_name = var.resource_group_name
allocation_method = "Static"
sku = "Standard"
domain_name_label = var.backend_host_name == null ? "${var.prefix}-appgateway" : null
tags = var.tags
}

resource "azurerm_web_application_firewall_policy" "waf_policy" {
count = var.waf_policy_enabled ? 1 : 0

name = "${var.prefix}-waf-policy"
resource_group_name = var.resource_group_name
location = var.location
tags = var.tags

dynamic "custom_rules" {
for_each = var.waf_policy_config.custom_rules
content {
name = custom_rules.value.name
priority = custom_rules.value.priority
rule_type = custom_rules.value.rule_type
action = custom_rules.value.action
dynamic "match_conditions" {
for_each = custom_rules.value.match_conditions
content {
operator = match_conditions.value.operator
negation_condition = match_conditions.value.negation_condition
match_values = match_conditions.value.match_values
dynamic "match_variables" {
for_each = match_conditions.value.match_variables
content {
variable_name = match_variables.value.variable_name
}
}
}
}
}
}

dynamic "policy_settings" {
for_each = var.waf_policy_config.policy_settings != null ? [var.waf_policy_config.policy_settings] : []
content {
enabled = policy_settings.value.enabled
mode = policy_settings.value.mode
request_body_check = policy_settings.value.request_body_check
file_upload_limit_in_mb = policy_settings.value.file_upload_limit_in_mb
max_request_body_size_in_kb = policy_settings.value.max_request_body_size_in_kb
}
}

managed_rules {
dynamic "exclusion" {
for_each = var.waf_policy_config.managed_rules.exclusion
content {
match_variable = exclusion.value.match_variable
selector = exclusion.value.selector
selector_match_operator = exclusion.value.selector_match_operator
dynamic "excluded_rule_set" {
for_each = exclusion.value.excluded_rule_set
content {
type = excluded_rule_set.value.type
version = excluded_rule_set.value.version
dynamic "rule_group" {
for_each = excluded_rule_set.value.rule_group
content {
rule_group_name = rule_group.value.rule_group_name
excluded_rules = rule_group.value.excluded_rules
}
}
}
}
}
}

dynamic "managed_rule_set" {
for_each = var.waf_policy_config.managed_rules.managed_rule_set
content {
type = managed_rule_set.value.type
version = managed_rule_set.value.version
dynamic "rule_group_override" {
for_each = managed_rule_set.value.rule_group_override
content {
rule_group_name = rule_group_override.value.rule_group_name
dynamic "rule" {
for_each = rule_group_override.value.rule
content {
id = rule.value.id
enabled = rule.value.enabled
action = rule.value.action
}
}
}
}
}
}
}
}


resource "azurerm_application_gateway" "appgateway" {
name = "${var.prefix}-appgateway"
resource_group_name = var.resource_group_name
location = var.location
firewall_policy_id = var.waf_policy_enabled ? azurerm_web_application_firewall_policy.waf_policy[0].id : null
force_firewall_policy_association = var.waf_policy_enabled ? true : false

sku {
name = var.waf_policy_enabled ? "WAF_v2" : var.sku
tier = var.waf_policy_enabled ? "WAF_v2" : "Standard_v2"
capacity = 2
}

gateway_ip_configuration {
name = "${var.prefix}-gateway-ip-configuration"
subnet_id = var.subnet_id
}

frontend_port {
name = local.frontend_port_name
port = var.port
}

frontend_ip_configuration {
name = local.frontend_ip_configuration_name
public_ip_address_id = azurerm_public_ip.gateway_ip.id
}

backend_address_pool {
name = local.backend_address_pool_name
fqdns = var.backend_address_pool_fqdn != null ? length(var.backend_address_pool_fqdn) != 0 ? var.backend_address_pool_fqdn : null : null
}

dynamic "trusted_root_certificate" {
for_each = var.backend_trusted_root_certificate == null ? [] : [1]

content {
name = "root-cert"
data = filebase64(var.backend_trusted_root_certificate)
}
}

dynamic "ssl_certificate" {
for_each = var.ssl_certificate == null ? [] : var.ssl_certificate

content {
name = "ListenerCert"
data = ssl_certificate.value.data != null ? filebase64(ssl_certificate.value.data) : null
password = ssl_certificate.value.password
key_vault_secret_id = ssl_certificate.value.data != null ? null : ssl_certificate.value.key_vault_secret_id
}
}

backend_http_settings {
name = local.http_setting_name
cookie_based_affinity = "Disabled"
port = var.port
protocol = var.protocol
request_timeout = 60
probe_name = var.probe != null ? "default-probe" : null
host_name = var.backend_host_name == null ? azurerm_public_ip.gateway_ip.fqdn : var.backend_host_name
trusted_root_certificate_names = var.backend_trusted_root_certificate == null ? null : ["root-cert"]
}

http_listener {
name = local.listener_name
frontend_ip_configuration_name = local.frontend_ip_configuration_name
frontend_port_name = local.frontend_port_name
protocol = var.protocol
ssl_certificate_name = var.ssl_certificate == null ? null : "ListenerCert"
}

request_routing_rule {
name = local.request_routing_rule_name
rule_type = "Basic"
http_listener_name = local.listener_name
backend_address_pool_name = local.backend_address_pool_name
backend_http_settings_name = local.http_setting_name
priority = 1
}

dynamic "probe" {
for_each = var.probe != null ? var.probe : []

content {
name = probe.value.name
interval = 60
protocol = var.protocol
path = probe.value.path
timeout = 30
unhealthy_threshold = 3
pick_host_name_from_backend_http_settings = true
}
}

tags = var.tags

depends_on = [azurerm_web_application_firewall_policy.waf_policy]
}
6 changes: 6 additions & 0 deletions modules/azurerm_app_gateway/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright © 2020-2023, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

output "gateway_frontend_ip" {
value = azurerm_public_ip.gateway_ip.ip_address
}
86 changes: 86 additions & 0 deletions modules/azurerm_app_gateway/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Copyright © 2020-2023, SAS Institute Inc., Cary, NC, USA. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

variable "prefix" {
description = "A prefix used in the name for all the Azure resources created by this script."
type = string
}

variable "resource_group_name" {
description = "The name of the resource group in which to create the Azure Application Gateway. Changing this forces a new resource to be created."
type = string
}

variable "location" {
description = "Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created."
type = string
}

variable "subnet_id" {
description = "The ID of the Subnet which the Application Gateway should be connected to."
type = string
}

variable "tags" {
description = "Map of common tags to be placed on the Resources"
type = map(any)
}

variable "sku" {
description = "The Name of the SKU to use for this Application Gateway."
type = string
}

variable "port" {
description = "The port which should be used for this Application Gateway."
type = string
}

variable "protocol" {
description = "The Protocol which should be used. Possible values are Http and Https."
type = string
}

variable "backend_host_name" {
description = "Host header to be sent to the backend servers."
type = string
default = null
}

variable "backend_trusted_root_certificate" {
description = "The Trusted Root Certificate to use."
type = string
default = null
}

variable "ssl_certificate" {
description = "The associated SSL Certificate which should be used for this HTTP Listener."
type = any
default = null
}

variable "backend_address_pool_fqdn" {
description = "A list of FQDN's which should be part of the Backend Address Pool."
type = list(any)
}

variable "identity_ids" {
description = "Specifies a list of User Assigned Managed Identity IDs to be assigned to this Application Gateway."
type = list(any)
default = null
}

variable "waf_policy_enabled" {
description = "Is the Web Application Firewall enabled?"
type = bool
}

variable "waf_policy_config" {
description = "Azure Web Application Firewall Policy instance configuration."
type = any
}

variable "probe" {
description = "Health probes to be created for the Application Gateway."
type = any
}
9 changes: 9 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,12 @@ output "message_broker_primary_key" {
output "message_broker_name" {
value = var.create_azure_message_broker ? var.message_broker_name : null
}

## Application Gateway
output "app_gateway_enabled" {
value = var.create_app_gateway ? var.create_app_gateway : null
}

output "app_gateway_frontend_ip" {
value = var.create_app_gateway ? module.app_gateway[0].gateway_frontend_ip : null
}
Loading

0 comments on commit 020ffe9

Please sign in to comment.