An open API service indexing awesome lists of open source software.

https://github.com/launchbynttdata/tf-azurerm-module_reference-application_gateway


https://github.com/launchbynttdata/tf-azurerm-module_reference-application_gateway

azure reference-architecture terraform

Last synced: 2 months ago
JSON representation

Awesome Lists containing this project

README

        

# tf-azurerm-module_reference-application_gateway

[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![License: CC BY-NC-ND 4.0](https://img.shields.io/badge/License-CC_BY--NC--ND_4.0-lightgrey.svg)](https://creativecommons.org/licenses/by-nc-nd/4.0/)

## Overview

This terraform module provisions an Azure Application Gateway with all its dependencies. It supports the SKUs `Standard_V2` and
`WAF_V2`. At the time of creating this module, its possible to provision either Public only or both Private and public
Application Gateway instance. The Private only is currently in Preview and is not supported by this module. The only input to this module is the
subnet in which the Application Gateway should be deployed.

This reference module is built as a wrapper around the primitive module [tf-azurerm-module_primitive-application_gateway](https://github.com/launchbynttdata/tf-azurerm-module_primitive-application_gateway)

It provisions the following resources:
- Resource Group
- Application Gateway
- WAF (optional)
- Public IP
- Custom Domain Name
- TLS Certificates for listeners
- User Assigned Managed Identity (MSI)
- Role Assignment for MSI to access services like KeyVault

## Pre-Commit hooks

[.pre-commit-config.yaml](.pre-commit-config.yaml) file defines certain `pre-commit` hooks that are relevant to terraform, golang and common linting tasks. There are no custom hooks added.

`commitlint` hook enforces commit message in certain format. The commit contains the following structural elements, to communicate intent to the consumers of your commit messages:

- **fix**: a commit of the type `fix` patches a bug in your codebase (this correlates with PATCH in Semantic Versioning).
- **feat**: a commit of the type `feat` introduces a new feature to the codebase (this correlates with MINOR in Semantic Versioning).
- **BREAKING CHANGE**: a commit that has a footer `BREAKING CHANGE:`, or appends a `!` after the type/scope, introduces a breaking API change (correlating with MAJOR in Semantic Versioning). A BREAKING CHANGE can be part of commits of any type.
footers other than BREAKING CHANGE: may be provided and follow a convention similar to git trailer format.
- **build**: a commit of the type `build` adds changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
- **chore**: a commit of the type `chore` adds changes that don't modify src or test files
- **ci**: a commit of the type `ci` adds changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
- **docs**: a commit of the type `docs` adds documentation only changes
- **perf**: a commit of the type `perf` adds code change that improves performance
- **refactor**: a commit of the type `refactor` adds code change that neither fixes a bug nor adds a feature
- **revert**: a commit of the type `revert` reverts a previous commit
- **style**: a commit of the type `style` adds code changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- **test**: a commit of the type `test` adds missing tests or correcting existing tests

Base configuration used for this project is [commitlint-config-conventional (based on the Angular convention)](https://github.com/conventional-changelog/commitlint/tree/master/@commitlint/config-conventional#type-enum)

If you are a developer using vscode, [this](https://marketplace.visualstudio.com/items?itemName=joshbolduc.commitlint) plugin may be helpful.

`detect-secrets-hook` prevents new secrets from being introduced into the baseline. TODO: INSERT DOC LINK ABOUT HOOKS

In order for `pre-commit` hooks to work properly

- You need to have the pre-commit package manager installed. [Here](https://pre-commit.com/#install) are the installation instructions.
- `pre-commit` would install all the hooks when commit message is added by default except for `commitlint` hook. `commitlint` hook would need to be installed manually using the command below

```
pre-commit install --hook-type commit-msg
```

## To test the resource group module locally

1. For development/enhancements to this module locally, you'll need to install all of its components. This is controlled by the `configure` target in the project's [`Makefile`](./Makefile). Before you can run `configure`, familiarize yourself with the variables in the `Makefile` and ensure they're pointing to the right places.

```
make configure
```

This adds in several files and directories that are ignored by `git`. They expose many new Make targets.

2. _THIS STEP APPLIES ONLY TO MICROSOFT AZURE. IF YOU ARE USING A DIFFERENT PLATFORM PLEASE SKIP THIS STEP._ The first target you care about is `env`. This is the common interface for setting up environment variables. The values of the environment variables will be used to authenticate with cloud provider from local development workstation.

`make configure` command will bring down `azure_env.sh` file on local workstation. Devloper would need to modify this file, replace the environment variable values with relevant values.

These environment variables are used by `terratest` integration suit.

Service principle used for authentication(value of ARM_CLIENT_ID) should have below privileges on resource group within the subscription.

```
"Microsoft.Resources/subscriptions/resourceGroups/write"
"Microsoft.Resources/subscriptions/resourceGroups/read"
"Microsoft.Resources/subscriptions/resourceGroups/delete"
```

Then run this make target to set the environment variables on developer workstation.

```
make env
```

3. The first target you care about is `check`.

**Pre-requisites**
Before running this target it is important to ensure that, developer has created files mentioned below on local workstation under root directory of git repository that contains code for primitives/segments. Note that these files are `azure` specific. If primitive/segment under development uses any other cloud provider than azure, this section may not be relevant.

- A file named `provider.tf` with contents below

```
provider "azurerm" {
features {}
}
```

- A file named `terraform.tfvars` which contains key value pair of variables used.

Note that since these files are added in `gitignore` they would not be checked in into primitive/segment's git repo.

After creating these files, for running tests associated with the primitive/segment, run

```
make check
```

If `make check` target is successful, developer is good to commit the code to primitive/segment's git repo.

`make check` target

- runs `terraform commands` to `lint`,`validate` and `plan` terraform code.
- runs `conftests`. `conftests` make sure `policy` checks are successful.
- runs `terratest`. This is integration test suit.
- runs `opa` tests

## Requirements

| Name | Version |
|------|---------|
| [terraform](#requirement\_terraform) | <= 1.5.5 |
| [azurerm](#requirement\_azurerm) | ~> 3.77 |

## Providers

No providers.

## Modules

| Name | Source | Version |
|------|--------|---------|
| [resource\_names](#module\_resource\_names) | terraform.registry.launch.nttdata.com/module_library/resource_name/launch | ~> 1.0 |
| [resource\_names\_v2](#module\_resource\_names\_v2) | terraform.registry.launch.nttdata.com/module_library/resource_name/launch | ~> 2.0 |
| [resource\_group](#module\_resource\_group) | terraform.registry.launch.nttdata.com/module_primitive/resource_group/azurerm | ~> 1.0 |
| [public\_ip](#module\_public\_ip) | terraform.registry.launch.nttdata.com/module_primitive/public_ip/azurerm | ~> 1.0 |
| [managed\_identity](#module\_managed\_identity) | terraform.registry.launch.nttdata.com/module_primitive/user_managed_identity/azurerm | ~> 1.0 |
| [identity\_roles](#module\_identity\_roles) | terraform.registry.launch.nttdata.com/module_primitive/role_assignment/azurerm | ~> 1.0 |
| [private\_dns\_record](#module\_private\_dns\_record) | terraform.registry.launch.nttdata.com/module_primitive/private_dns_records/azurerm | ~> 1.0 |
| [application\_gateway](#module\_application\_gateway) | terraform.registry.launch.nttdata.com/module_primitive/application_gateway/azurerm | ~> 1.0 |

## Resources

No resources.

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| [product\_family](#input\_product\_family) | (Required) Name of the product family for which the resource is created.
Example: org\_name, department\_name. | `string` | `"dso"` | no |
| [product\_service](#input\_product\_service) | (Required) Name of the product service for which the resource is created.
For example, backend, frontend, middleware etc. | `string` | `"app"` | no |
| [environment](#input\_environment) | Environment in which the resource should be provisioned like dev, qa, prod etc. | `string` | `"dev"` | no |
| [environment\_number](#input\_environment\_number) | The environment count for the respective environment. Defaults to 000. Increments in value of 1 | `string` | `"000"` | no |
| [resource\_number](#input\_resource\_number) | The resource count for the respective resource. Defaults to 000. Increments in value of 1 | `string` | `"000"` | no |
| [region](#input\_region) | AWS Region in which the infra needs to be provisioned | `string` | `"eastus"` | no |
| [resource\_names\_map](#input\_resource\_names\_map) | A map of key to resource\_name that will be used by tf-launch-module\_library-resource\_name to generate resource names |

map(object(
{
name = string
max_length = optional(number, 60)
}
))
|
{
"app_gateway": {
"max_length": 60,
"name": "appgw"
},
"msi": {
"max_length": 60,
"name": "msi"
},
"nsg": {
"max_length": 60,
"name": "nsg"
},
"public_ip": {
"max_length": 60,
"name": "pip"
},
"resource_group": {
"max_length": 60,
"name": "rg"
}
}
| no |
| [resource\_names\_version](#input\_resource\_names\_version) | Major version of the resource names module to use | `string` | `"1"` | no |
| [frontend\_ip\_configuration\_name](#input\_frontend\_ip\_configuration\_name) | Name of the frontend IP configuration. | `string` | `"standard-public-ip"` | no |
| [frontend\_private\_ip\_configuration\_name](#input\_frontend\_private\_ip\_configuration\_name) | Name of the frontend private IP configuration. Mandatory when appgw\_private is set to true. | `string` | `"standard-private-ip"` | no |
| [gateway\_ip\_configuration\_name](#input\_gateway\_ip\_configuration\_name) | Name of the gateway IP configuration. | `string` | `"app-gateway-ip"` | no |
| [sku\_capacity](#input\_sku\_capacity) | The Capacity of the SKU to use for this Application Gateway - which must be between 1 and 10, optional if autoscale\_configuration is set | `number` | `2` | no |
| [sku](#input\_sku) | The Name of the SKU to use for this Application Gateway. Possible values are Standard\_v2 and WAF\_v2. | `string` | `"Standard_v2"` | no |
| [zones](#input\_zones) | A collection of availability zones to spread the Application Gateway over. This option is only supported for v2 SKUs | `list(number)` |
[
1,
2,
3
]
| no |
| [frontend\_port\_settings](#input\_frontend\_port\_settings) | Frontend port settings. Each port setting contains the name and the port for the frontend port. |
list(object({
name = string
port = number
}))
| n/a | yes |
| [ssl\_policy](#input\_ssl\_policy) | Application Gateway SSL configuration. The list of available policies can be found here: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/application_gateway#disabled_protocols |
object({
disabled_protocols = optional(list(string), [])
policy_type = optional(string, "Predefined")
policy_name = optional(string, "AppGwSslPolicy20170401S")
cipher_suites = optional(list(string), [])
min_protocol_version = optional(string, "TLSv1_2")
})
| `null` | no |
| [ssl\_profile](#input\_ssl\_profile) | Application Gateway SSL profile. Default profile is used when this variable is set to null. https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/application_gateway#name |
list(object({
name = string
trusted_client_certificate_names = optional(list(string), [])
verify_client_cert_issuer_dn = optional(bool, false)
ssl_policy = optional(object({
disabled_protocols = optional(list(string), [])
policy_type = optional(string, "Predefined")
policy_name = optional(string, "AppGwSslPolicy20170401S")
cipher_suites = optional(list(string), [])
min_protocol_version = optional(string, "TLSv1_2")
}))
}))
| `[]` | no |
| [firewall\_policy\_id](#input\_firewall\_policy\_id) | ID of a Web Application Firewall Policy | `string` | `null` | no |
| [trusted\_root\_certificate\_configs](#input\_trusted\_root\_certificate\_configs) | List of trusted root certificates. `file_path` is checked first, using `data` (base64 cert content) if null. This parameter is required if you are not using a trusted certificate authority (eg. selfsigned certificate). |
list(object({
name = string
data = optional(string)
file_path = optional(string)
key_vault_secret_id = optional(string)
}))
| `[]` | no |
| [appgw\_backend\_pools](#input\_appgw\_backend\_pools) | List of objects with backend pool configurations. |
list(object({
name = string
fqdns = optional(list(string))
ip_addresses = optional(list(string))
}))
| n/a | yes |
| [appgw\_http\_listeners](#input\_appgw\_http\_listeners) | List of objects with HTTP listeners configurations and custom error configurations.
The field `frontend_ip_configuration_name` may not be set. By default, the listener attaches to the public IP of the App Gateway.
If appgw\_private is set to true, the listener will attach to the private IP of the App Gateway.
If user needs to override this behavior, they can set the `frontend_ip_configuration_name` to the name of the frontend IP configuration. |
list(object({
name = string

frontend_ip_configuration_name = optional(string)
frontend_port_name = optional(string)
host_name = optional(string)
host_names = optional(list(string))
protocol = optional(string, "Https")
require_sni = optional(bool, false)
ssl_certificate_name = optional(string)
ssl_profile_name = optional(string)
firewall_policy_id = optional(string)

custom_error_configuration = optional(list(object({
status_code = string
custom_error_page_url = string
})), [])
}))
| n/a | yes |
| [custom\_error\_configuration](#input\_custom\_error\_configuration) | List of objects with global level custom error configurations. |
list(object({
status_code = string
custom_error_page_url = string
}))
| `[]` | no |
| [ssl\_certificates\_configs](#input\_ssl\_certificates\_configs) | List of objects with SSL certificates configurations.
The path to a base-64 encoded certificate is expected in the 'data' attribute:
data = filebase64("./file_path")
|
list(object({
name = string
data = optional(string)
password = optional(string)
key_vault_secret_id = optional(string)
}))
| `[]` | no |
| [authentication\_certificates\_configs](#input\_authentication\_certificates\_configs) | List of objects with authentication certificates configurations.
The path to a base-64 encoded certificate is expected in the 'data' attribute:
data = filebase64("./file_path")
|
list(object({
name = string
data = string
}))
| `[]` | no |
| [trusted\_client\_certificates\_configs](#input\_trusted\_client\_certificates\_configs) | List of objects with trusted client certificates configurations.
The path to a base-64 encoded certificate is expected in the 'data' attribute:
data = filebase64("./file_path")
|
list(object({
name = string
data = string
}))
| `[]` | no |
| [appgw\_routings](#input\_appgw\_routings) | List of objects with request routing rules configurations. With AzureRM v3+ provider, `priority` attribute becomes mandatory.
Each Routing rule is associated with a particular listener and determines how traffic are routed to the backend pool.
Multiple routing rules cannot be associated with the same listener.

rule\_type="PathBasedRouting" can be used to route traffic to multiple backends based on the URL path, else rule\_type="Basic" is used.

`url_path_map_name` is required when rule\_type="PathBasedRouting" and is used to define the URL path map configuration. |
list(object({
name = string
rule_type = optional(string, "Basic")
http_listener_name = optional(string)
backend_address_pool_name = optional(string)
backend_http_settings_name = optional(string)
url_path_map_name = optional(string)
redirect_configuration_name = optional(string)
rewrite_rule_set_name = optional(string)
priority = optional(number)
}))
| n/a | yes |
| [appgw\_probes](#input\_appgw\_probes) | List of objects with probes configurations.
Probes are used to determine the health of the backend servers.
User needs to define custom probes only when the default probe is not sufficient, for example when the backend server
uses a different port or path or protocol.

Additional checks can be added to the default probe by setting the `match` attribute to compare the return status code
or the response body |
list(object({
name = string
host = optional(string)
port = optional(number, null)
interval = optional(number, 30)
path = optional(string, "/")
protocol = optional(string, "Https")
timeout = optional(number, 30)

unhealthy_threshold = optional(number, 3)
pick_host_name_from_backend_http_settings = optional(bool, false)
minimum_servers = optional(number, 0)

match = optional(object({
body = optional(string, "")
status_code = optional(list(string), ["200-399"])
}), {})
}))
| `[]` | no |
| [appgw\_backend\_http\_settings](#input\_appgw\_backend\_http\_settings) | List of objects including backend http settings configurations.
Each backend pool must be associated with a backend http settings configuration. |
list(object({
name = string
port = optional(number, 443)
protocol = optional(string, "Https")

path = optional(string)
probe_name = optional(string)

cookie_based_affinity = optional(string, "Disabled")
affinity_cookie_name = optional(string, "ApplicationGatewayAffinity")
request_timeout = optional(number, 20)
host_name = optional(string)
pick_host_name_from_backend_address = optional(bool, true)
trusted_root_certificate_names = optional(list(string), [])
authentication_certificate = optional(string)

connection_draining_timeout_sec = optional(number)
}))
| n/a | yes |
| [appgw\_url\_path\_map](#input\_appgw\_url\_path\_map) | List of objects with URL path map configurations.
This is mandatory when the routing rule\_type is set to "PathBasedRouting". Path mapping must be specified to
route traffic to multiple backends based on the URL path. |
list(object({
name = string

default_backend_address_pool_name = optional(string)
default_redirect_configuration_name = optional(string)
default_backend_http_settings_name = optional(string)
default_rewrite_rule_set_name = optional(string)

path_rules = list(object({
name = string

backend_address_pool_name = optional(string)
backend_http_settings_name = optional(string)
rewrite_rule_set_name = optional(string)
redirect_configuration_name = optional(string)

paths = optional(list(string), [])
}))
}))
| `[]` | no |
| [appgw\_redirect\_configuration](#input\_appgw\_redirect\_configuration) | List of objects with redirect configurations. |
list(object({
name = string

redirect_type = optional(string, "Permanent")
target_listener_name = optional(string)
target_url = optional(string)

include_path = optional(bool, true)
include_query_string = optional(bool, true)
}))
| `[]` | no |
| [appgw\_rewrite\_rule\_set](#input\_appgw\_rewrite\_rule\_set) | List of rewrite rule set objects with rewrite rules. |
list(object({
name = string
rewrite_rules = list(object({
name = string
rule_sequence = string

conditions = optional(list(object({
variable = string
pattern = string
ignore_case = optional(bool, false)
negate = optional(bool, false)
})), [])

response_header_configurations = optional(list(object({
header_name = string
header_value = string
})), [])

request_header_configurations = optional(list(object({
header_name = string
header_value = string
})), [])

url_reroute = optional(object({
path = optional(string)
query_string = optional(string)
components = optional(string)
reroute = optional(bool)
}))
}))
}))
| `[]` | no |
| [force\_firewall\_policy\_association](#input\_force\_firewall\_policy\_association) | Enable if the Firewall Policy is associated with the Application Gateway. | `bool` | `false` | no |
| [waf\_configuration](#input\_waf\_configuration) | WAF configuration object (only available with WAF\_v2 SKU) with following attributes:
- enabled:                  Boolean to enable WAF.
- file_upload_limit_mb: The File Upload Limit in MB. Accepted values are in the range 1MB to 500MB.
- firewall_mode: The Web Application Firewall Mode. Possible values are Detection and Prevention.
- max_request_body_size_kb: The Maximum Request Body Size in KB. Accepted values are in the range 1KB to 128KB.
- request_body_check: Is Request Body Inspection enabled ?
- rule_set_type: The Type of the Rule Set used for this Web Application Firewall.
- rule_set_version: The Version of the Rule Set used for this Web Application Firewall. Possible values are 2.2.9, 3.0, and 3.1.
- disabled_rule_group: The rule group where specific rules should be disabled. Accepted values can be found here: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/application_gateway#rule_group_name
- exclusion: WAF exclusion rules to exclude header, cookie or GET argument. More informations on: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/application_gateway#match_variable
|
object({
enabled = optional(bool, true)
file_upload_limit_mb = optional(number, 100)
firewall_mode = optional(string, "Prevention")
max_request_body_size_kb = optional(number, 128)
request_body_check = optional(bool, true)
rule_set_type = optional(string, "OWASP")
rule_set_version = optional(string, 3.1)
disabled_rule_group = optional(list(object({
rule_group_name = string
rules = optional(list(string))
})), [])
exclusion = optional(list(object({
match_variable = string
selector = optional(string)
selector_match_operator = optional(string)
})), [])
})
| `{}` | no |
| [disable\_waf\_rules\_for\_dev\_portal](#input\_disable\_waf\_rules\_for\_dev\_portal) | Whether to disable some WAF rules if the APIM developer portal is hosted behind this Application Gateway. See locals.tf for the documentation link. | `bool` | `false` | no |
| [subnet\_id](#input\_subnet\_id) | Subnet ID for attaching the Application Gateway. This is mandatory for v2 SKUs | `string` | n/a | yes |
| [private\_ip\_address](#input\_private\_ip\_address) | The private IP address of the Application Gateway. Must be within the range of the subnet. Required only when appgw\_private is set to true. | `string` | `""` | no |
| [user\_assigned\_identity\_id](#input\_user\_assigned\_identity\_id) | User assigned identity id assigned to this resource. User can choose to pass in an existing identity or create a new one with create\_user\_managed\_identity. | `string` | `null` | no |
| [create\_user\_managed\_identity](#input\_create\_user\_managed\_identity) | Creates an user assigned managed Identity and assigns it to the Application Gateway. If this is true, user\_assigned\_identity\_id will be ignored. | `bool` | `true` | no |
| [appgw\_private](#input\_appgw\_private) | Boolean variable to create a private Application Gateway. When `true`, the default http listener will listen on private IP instead of the public IP. | `bool` | `false` | no |
| [enable\_http2](#input\_enable\_http2) | Whether to enable http2 or not | `bool` | `true` | no |
| [autoscaling\_parameters](#input\_autoscaling\_parameters) | Map containing autoscaling parameters. Must contain at least min\_capacity |
object({
min_capacity = number
max_capacity = optional(number, 5)
})
| `null` | no |
| [role\_assignments](#input\_role\_assignments) | A map of role assignments to be associated with the user assigned managed identity of the Application Gateway
Should be of the format
{
private-dns = ["Private DNS Zone Contributor", ""]
key-vault = ["Key Vault Administrator", ""]
} | `map(list(string))` | `{}` | no |
| [custom\_private\_dns\_record](#input\_custom\_private\_dns\_record) | Custom private DNS record for the Application Gateway. An A-record would be created for the private IP address.
Valid `private_dns_zone_name` and `private_dns_zone_rg` must be provided. `name` must be only the sub-domain without the zone name. |
object({
name = string
ttl = optional(number, 300)
private_dns_zone_name = string
private_dns_zone_rg = string
})
| `null` | no |
| [tags](#input\_tags) | A mapping of tags to assign to the resource. | `map(string)` | `{}` | no |

## Outputs

| Name | Description |
|------|-------------|
| [id](#output\_id) | The ID of the Application Gateway. |
| [name](#output\_name) | The name of the Application Gateway. |
| [frontend\_ip\_configuration](#output\_frontend\_ip\_configuration) | The frontend IP configuration of the Application Gateway. |
| [frontend\_port](#output\_frontend\_port) | The frontend port of the Application Gateway. |
| [backend\_address\_pool](#output\_backend\_address\_pool) | The backend address pool of the Application Gateway. |