diff --git a/modules/azure-app-gateway/README.md b/modules/azure-app-gateway/README.md index 0e40deee0..3a78357d0 100644 --- a/modules/azure-app-gateway/README.md +++ b/modules/azure-app-gateway/README.md @@ -1,3 +1,282 @@ + +# Azure Application Gateway Terraform Module + +## Overview + +Este módulo de Terraform proporciona una solución flexible y productiva para desplegar y gestionar **Azure Application Gateway** en Azure. Permite la configuración avanzada de listeners, reglas de enrutamiento, certificados SSL, perfiles de seguridad, WAF y más, siguiendo buenas prácticas de infraestructura como código. + +El módulo está diseñado para adaptarse tanto a despliegues simples como complejos, permitiendo la integración con identidades gestionadas, políticas de seguridad, certificados desde Key Vault y reglas personalizadas de firewall. + +## Características principales + +- Provisionamiento completo de Application Gateway: frontend, backend, listeners, reglas, certificados y WAF. +- Soporte para perfiles SSL y certificados de cliente. +- Integración con Azure Key Vault para gestión segura de certificados. +- Reglas de reescritura y enrutamiento avanzadas. +- Web Application Firewall (WAF) configurable. +- Etiquetado flexible y herencia de etiquetas del Resource Group. + +## Estructura de archivos + +``` +. +├── main.tf +├── variables.tf +├── outputs.tf +├── versions.tf +├── data.tf +├── public_ip.tf +├── web_application_firewall_policy.tf +├── locals_*.tf +├── docs/ +│ ├── header.md +│ └── footer.md +├── CHANGELOG.md +├── README.md +└── .terraform-docs.yml +``` + +## Ejemplo completo de uso + +```yaml +values: + tags_from_rg: true + resource_group_name: ${{ tfworkspace:example-rg:outputs.resource_group_name }} + user_assigned_identity: "example-identity" + subnet: + name: "example-subnet" + virtual_network_name: "example-vnet" + public_ip: + name: "example-public-ip" + sku: "Standard" + allocation_method: "Static" + ssl_profiles: + - name: "example-ssl-profile" + verify_client_cert_issuer_dn: true + verify_client_certificate_revocation: "OCSP" + ssl_policy: + disabled_protocols: + - "TLSv1_0" + - "TLSv1_1" + min_protocol_version: "TLSv1_2" + policy_name: "AppGwSslPolicy20170401S" + cipher_suites: + - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" + - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" + ca_certs_origin: + github_owner: "gh-owner" + github_repository: "gh-repo" + github_branch: "gh-branch" + github_directory: "gh-dir" + rewrite_rule_sets: + - name: example-rewrite + rewrite_rules: + - name: example-rule + rule_sequence: 300 + conditions: + - variable: http_request_uri + pattern: '.*.html$' + ignore_case: true + negate: false + - variable: http_request_method + pattern: '^POST$' + ignore_case: true + negate: true + request_header_configurations: + - header_name: X-Rewrite-Rule + header_value: applied + response_header_configurations: + - header_name: X-Cache-Control + header_value: max-age=3600 + - header_name: X-Server + header_value: custom-app + url_rewrite: + source_path: '^/api/v1/(.*)' + components: path_only + reroute: false + web_application_firewall_policy: + name: "example-waf-policy" + policy_settings: + enabled: true + mode: "Detection" + request_body_check: true + file_upload_limit_in_mb: 100 + max_request_body_size_in_kb: 128 + custom_rules: + - name: "HeaderName" + enabled: true + priority: 1 + rule_type: "MatchRule" + action: "Allow" + match_conditions: + - match_values: + - "example.com" + operator: "Equal" + match_variables: + - variable_name: "RequestHeaders" + selector: "Host" + - name: "BlockUserAgentWindows" + enabled: true + priority: 2 + rule_type: "MatchRule" + action: "Block" + match_conditions: + - operator: "Contains" + negation_condition: false + match_values: + - "Windows" + match_variables: + - variable_name: "RequestHeaders" + selector: "UserAgent" + managed_rule_set: + - type: "OWASP" + version: "3.2" + rule_group_override: + - rule_group_name: "REQUEST-932-APPLICATION-ATTACK-RCE" + rule: + - id: "932100" + action: "AnomalyScoring" + enabled: false + - id: "932110" + action: "AnomalyScoring" + enabled: false + - rule_group_name: "REQUEST-942-APPLICATION-ATTACK-SQLI" + rule: + - id: "942430" + action: "AnomalyScoring" + enabled: false + - type: "Microsoft_BotManagerRuleSet" + version: "0.1" + application_gateway: + name: "example-appgw" + identity: + type: "UserAssigned" + enable_http2: true + sku: + name: "WAF_v2" + tier: "WAF_v2" + capacity: 0 + gateway_ip_configuration: + name: "appGatewayIpConfig" + autoscale_configuration: + min_capacity: 0 + max_capacity: 10 + frontend_ports: + - name: "port_80" + port: 80 + - name: "port_443" + port: 443 + frontend_ip_configuration: + name: "appGwPublicFrontendIpIPv4" + private_ip_address_allocation: "Dynamic" + ssl_certificates: + - name: "example-cert-1" + key_vault_secret_id: "https://example-kv.vault.azure.net/secrets/example-cert-1" + - name: "example-cert-2" + key_vault_secret_id: "https://example-kv.vault.azure.net/secrets/example-cert-2" + blocks_defaults: + backend_http_settings: + cookie_based_affinity: "Disabled" + pick_host_name_from_backend_address: false + port: 80 + protocol: "Http" + request_timeout: 20 + trusted_root_certificate_names: [] + http_listeners: + https: + frontend_ip_configuration_name: "appGwPublicFrontendIpIPv4" + frontend_port_name: "port_443" + protocol: "Https" + ssl_certificate_name: "example-cert-2" + ssl_profile_name: "example-ssl-profile" + http-redirection: + frontend_ip_configuration_name: "appGwPublicFrontendIpIPv4" + frontend_port_name: "port_80" + protocol: "Http" + require_sni: false + probe: + host: "10.0.0.1" + interval: 10 + minimum_servers: 0 + path: "/" + pick_host_name_from_backend_http_settings: false + protocol: "Http" + timeout: 30 + unhealthy_threshold: 3 + matches: + - status_code: ["200-399", "404"] + redirect_configuration: + include_path: true + include_query_string: true + redirect_type: "Permanent" + request_routing_rules: + http-redirection: + rule_type: "Basic" + rewrite_rule_set_name: example-rewrite + https: + rule_type: "Basic" + rewrite_rule_set_name: example-rewrite + blocks: + organization1: + app1: + pro: + backend_http_settings: + request_timeout: 90 + redirect_configuration: {} + backend_address_pool: + ip_addresses: + - 10.0.0.2 + http_listeners: + https: + host_names: + - "example.com" + ssl_certificate_name: "example-cert-1" + http-redirection: + host_names: + - "example.com" + probe: + host: "10.0.0.2" + request_routing_rules: + http-redirection: + priority: 10 + name: "redirect-example" + redirect_configuration_name: "redirect-example" + https: + backend_address_pool_name: "backend_address_pool-example" + backend_http_settings_name: "backend_http_settings-example" + priority: 11 + name: "request_routing_rule-example" + organization2: + app1: + pro: + backend_http_settings: + request_timeout: 60 + redirect_configuration: {} + backend_address_pool: + ip_addresses: + - 10.0.0.3 + http_listeners: + https: + host_names: + - "another-example.com" + ssl_certificate_name: "example-cert-1" + http-redirection: + host_names: + - "another-example.com" + probe: + host: "10.0.0.3" + request_routing_rules: + http-redirection: + priority: 20 + name: "redirect-another-example" + redirect_configuration_name: "redirect-another-example" + https: + backend_address_pool_name: "backend_address_pool-another-example" + backend_http_settings_name: "backend_http_settings-another-example" + priority: 21 + name: "request_routing_rule-another-example" +``` + ## Requirements | Name | Version | @@ -10,6 +289,11 @@ | Name | Version | |------|---------| | [azurerm](#provider\_azurerm) | 4.47.0 | +| [external](#provider\_external) | n/a | + +## Modules + +No modules. ## Resources @@ -45,260 +329,23 @@ | Name | Description | |------|-------------| -| [id](#output\_id) | The ID of the Application Gateway. | +| [id](#output\_id) | n/a | -## Example +--- -```yaml - values: - # Data values - tags_from_rg: true - resource_group_name: ${{ tfworkspace:example-rg:outputs.resource_group_name }} - user_assigned_identity: "example-identity" +## Examples - subnet: - name: "example-subnet" - virtual_network_name: "example-vnet" +For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/azure-app-gateway/_examples): - # Public IP - public_ip: - name: "example-public-ip" - sku: "Standard" - allocation_method: "Static" - - # SSL Profiles - ssl_profiles: - - name: "example-ssl-profile" - verify_client_cert_issuer_dn: true - verify_client_certificate_revocation: "OCSP" - ssl_policy: - disabled_protocols: - - "TLSv1_0" - - "TLSv1_1" - min_protocol_version: "TLSv1_2" - policy_name: "AppGwSslPolicy20170401S" - cipher_suites: - - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" - - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" - ca_certs_origin: - github_owner: "gh-owner" - github_repository: "gh-repo" - github_branch: "gh-branch" - github_directory: "gh-dir" +- [basic](https://github.com/prefapp/tfm/tree/main/modules/azure-app-gateway/_examples/basic) - Application Gateway with public IP, WAF policy, SSL profiles and rewrite rules. - # Rewrite Rule Sets - rewrite_rule_sets: - - name: example-rewrite - rewrite_rules: - - name: example-rule - rule_sequence: 300 - conditions: - - variable: http_request_uri - pattern: '.*\.html$' - ignore_case: true - negate: false - - variable: http_request_method - pattern: '^POST$' - ignore_case: true - negate: true - request_header_configurations: - - header_name: X-Rewrite-Rule - header_value: applied - response_header_configurations: - - header_name: X-Cache-Control - header_value: max-age=3600 - - header_name: X-Server - header_value: custom-app - url_rewrite: - source_path: '^/api/v1/(.*)' - components: path_only # Only possible values "path_only" or "query_string_only", if using both leave null - reroute: false +## Recursos adicionales - # WAF - web_application_firewall_policy: - name: "example-waf-policy" - policy_settings: - enabled: true - mode: "Detection" - request_body_check: true - file_upload_limit_in_mb: 100 - max_request_body_size_in_kb: 128 - custom_rules: - - name: "HeaderName" - enabled: true - priority: 1 - rule_type: "MatchRule" - action: "Allow" - match_conditions: - - match_values: - - "example.com" - operator: "Equal" - match_variables: - - variable_name: "RequestHeaders" - selector: "Host" - - name: "BlockUserAgentWindows" - enabled: true - priority: 2 - rule_type: "MatchRule" - action: "Block" - match_conditions: - - operator: "Contains" - negation_condition: false - match_values: - - "Windows" - match_variables: - - variable_name: "RequestHeaders" - selector: "UserAgent" - managed_rule_set: - - type: "OWASP" - version: "3.2" - rule_group_override: - - rule_group_name: "REQUEST-932-APPLICATION-ATTACK-RCE" - rule: - - id: "932100" - action: "AnomalyScoring" - enabled: false - - id: "932110" - action: "AnomalyScoring" - enabled: false - - rule_group_name: "REQUEST-942-APPLICATION-ATTACK-SQLI" - rule: - - id: "942430" - action: "AnomalyScoring" - enabled: false - - type: "Microsoft_BotManagerRuleSet" - version: "0.1" - # AppGW - application_gateway: - name: "example-appgw" - identity: - type: "UserAssigned" - enable_http2: true - sku: - name: "WAF_v2" - tier: "WAF_v2" - capacity: 0 - gateway_ip_configuration: - name: "appGatewayIpConfig" - autoscale_configuration: - min_capacity: 0 - max_capacity: 10 - frontend_ports: - - name: "port_80" - port: 80 - - name: "port_443" - port: 443 - frontend_ip_configuration: - name: "appGwPublicFrontendIpIPv4" - private_ip_address_allocation: "Dynamic" - ssl_certificates: - - name: "example-cert-1" - key_vault_secret_id: "https://example-kv.vault.azure.net/secrets/example-cert-1" - - name: "example-cert-2" - key_vault_secret_id: "https://example-kv.vault.azure.net/secrets/example-cert-2" +- [Azure Application Gateway](https://learn.microsoft.com/en-us/azure/application-gateway/overview) +- [Proveedor Terraform AzureRM](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/application_gateway) +- [Documentación oficial de Terraform](https://www.terraform.io/docs) - # Default blocks configuration - blocks_defaults: - backend_http_settings: - cookie_based_affinity: "Disabled" - pick_host_name_from_backend_address: false - port: 80 - protocol: "Http" - request_timeout: 20 - trusted_root_certificate_names: [] - http_listeners: - https: - frontend_ip_configuration_name: "appGwPublicFrontendIpIPv4" - frontend_port_name: "port_443" - protocol: "Https" - ssl_certificate_name: "example-cert-2" - ssl_profile_name: "example-ssl-profile" - http-redirection: - frontend_ip_configuration_name: "appGwPublicFrontendIpIPv4" - frontend_port_name: "port_80" - protocol: "Http" - require_sni: false - probe: - host: "10.0.0.1" - interval: 10 - minimum_servers: 0 - path: "/" - pick_host_name_from_backend_http_settings: false - protocol: "Http" - timeout: 30 - unhealthy_threshold: 3 - matches: - - status_code: ["200-399", "404"] - redirect_configuration: - include_path: true - include_query_string: true - redirect_type: "Permanent" - request_routing_rules: - http-redirection: - rule_type: "Basic" - rewrite_rule_set_name: example-rewrite - https: - rule_type: "Basic" - rewrite_rule_set_name: example-rewrite +## Soporte - # Custom blocks configuration - blocks: - organization1: - app1: - pro: - backend_http_settings: - request_timeout: 90 - redirect_configuration: {} - backend_address_pool: - ip_addresses: - - 10.0.0.2 - http_listeners: - https: - host_names: - - "example.com" - ssl_certificate_name: "example-cert-1" - http-redirection: - host_names: - - "example.com" - probe: - host: "10.0.0.2" - request_routing_rules: - http-redirection: - priority: 10 - name: "redirect-example" - redirect_configuration_name: "redirect-example" - https: - backend_address_pool_name: "backend_address_pool-example" - backend_http_settings_name: "backend_http_settings-example" - priority: 11 - name: "request_routing_rule-example" - organization2: - app1: - pro: - backend_http_settings: - request_timeout: 60 - redirect_configuration: {} - backend_address_pool: - ip_addresses: - - 10.0.0.3 - http_listeners: - https: - host_names: - - "another-example.com" - ssl_certificate_name: "example-cert-1" - http-redirection: - host_names: - - "another-example.com" - probe: - host: "10.0.0.3" - request_routing_rules: - http-redirection: - priority: 20 - name: "redirect-another-example" - redirect_configuration_name: "redirect-another-example" - https: - backend_address_pool_name: "backend_address_pool-another-example" - backend_http_settings_name: "backend_http_settings-another-example" - priority: 21 - name: "request_routing_rule-another-example" -``` +Para dudas, incidencias o contribuciones, utiliza el issue tracker del repositorio: [https://github.com/prefapp/tfm/issues](https://github.com/prefapp/tfm/issues) + \ No newline at end of file diff --git a/modules/azure-app-gateway/_examples/basic/example.tf b/modules/azure-app-gateway/_examples/basic/example.tf new file mode 100644 index 000000000..72b29305c --- /dev/null +++ b/modules/azure-app-gateway/_examples/basic/example.tf @@ -0,0 +1,209 @@ +// Basic example: public Application Gateway with a simple HTTP/HTTPS configuration + +module "azure_app_gateway" { + source = "../../" + + resource_group_name = "example-rg" + location = "westeurope" + user_assigned_identity = "example-identity" + + subnet = { + name = "example-subnet" + virtual_network_name = "example-vnet" + } + + public_ip = { + name = "example-public-ip" + sku = "Standard" + allocation_method = "Static" + } + + ssl_profiles = [ + { + name = "example-ssl-profile" + verify_client_cert_issuer_dn = true + verify_client_certificate_revocation = "OCSP" + ssl_policy = { + disabled_protocols = ["TLSv1_0", "TLSv1_1"] + min_protocol_version = "TLSv1_2" + policy_name = "AppGwSslPolicy20170401S" + cipher_suites = [ + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" + ] + } + ca_certs_origin = { + github_owner = "gh-owner" + github_repository = "gh-repo" + github_branch = "gh-branch" + github_directory = "gh-dir" + } + } + ] + + rewrite_rule_sets = [ + { + name = "example-rewrite" + rewrite_rules = [ + { + name = "example-rule" + rule_sequence = 300 + conditions = [ + { + variable = "http_request_uri" + pattern = ".*.html$" + ignore_case = true + negate = false + }, + { + variable = "http_request_method" + pattern = "^POST$" + ignore_case = true + negate = true + } + ] + request_header_configurations = [ + { + header_name = "X-Rewrite-Rule" + header_value = "applied" + } + ] + response_header_configurations = [ + { + header_name = "X-Cache-Control" + header_value = "max-age=3600" + }, + { + header_name = "X-Server" + header_value = "custom-app" + } + ] + url_rewrite = { + source_path = "^/api/v1/(.*)" + components = "path_only" + reroute = false + } + } + ] + } + ] + + web_application_firewall_policy = { + name = "example-waf-policy" + policy_settings = { + enabled = true + mode = "Detection" + request_body_check = true + file_upload_limit_in_mb = 100 + max_request_body_size_in_kb = 128 + } + custom_rules = [ + { + name = "HeaderName" + enabled = true + priority = 1 + rule_type = "MatchRule" + action = "Allow" + match_conditions = [ + { + match_values = ["example.com"] + operator = "Equal" + match_variables = [ + { + variable_name = "RequestHeaders" + selector = "Host" + } + ] + } + ] + }, + { + name = "BlockUserAgentWindows" + enabled = true + priority = 2 + rule_type = "MatchRule" + action = "Block" + match_conditions = [ + { + operator = "Contains" + negation_condition = false + match_values = ["Windows"] + match_variables = [ + { + variable_name = "RequestHeaders" + selector = "UserAgent" + } + ] + } + ] + } + ] + managed_rule_set = [ + { + type = "OWASP" + version = "3.2" + rule_group_override = [ + { + rule_group_name = "REQUEST-932-APPLICATION-ATTACK-RCE" + rule = [ + { + id = 932100 + action = "AnomalyScoring" + enabled = false + }, + { + id = 932110 + action = "AnomalyScoring" + enabled = false + } + ] + } + ] + } + ] + } + + application_gateway = { + name = "example-appgw" + identity = { + type = "UserAssigned" + } + enable_http2 = true + sku = { + name = "WAF_v2" + tier = "WAF_v2" + capacity = 0 + } + gateway_ip_configuration = { + name = "appGatewayIpConfig" + } + autoscale_configuration = { + min_capacity = 0 + max_capacity = 10 + } + frontend_ports = [ + { + name = "port_80" + port = 80 + }, + { + name = "port_443" + port = 443 + } + ] + frontend_ip_configuration = { + name = "appGwPublicFrontendIpIPv4" + private_ip_address_allocation = "Dynamic" + } + ssl_certificates = [ + { + name = "example-cert-1" + key_vault_secret_id = "https://example-kv.vault.azure.net/secrets/example-cert-1" + } + ] + } + + tags = { + environment = "dev" + } +} \ No newline at end of file diff --git a/modules/azure-app-gateway/_examples/basic/example.yaml b/modules/azure-app-gateway/_examples/basic/example.yaml new file mode 100644 index 000000000..9d4f265c9 --- /dev/null +++ b/modules/azure-app-gateway/_examples/basic/example.yaml @@ -0,0 +1,133 @@ +# Basic example values for Azure Application Gateway module + +resource_group_name: example-rg +location: westeurope +user_assigned_identity: example-identity + +subnet: + name: example-subnet + virtual_network_name: example-vnet + +public_ip: + name: example-public-ip + sku: Standard + allocation_method: Static + +ssl_profiles: + - name: example-ssl-profile + verify_client_cert_issuer_dn: true + verify_client_certificate_revocation: OCSP + ssl_policy: + disabled_protocols: + - TLSv1_0 + - TLSv1_1 + min_protocol_version: TLSv1_2 + policy_name: AppGwSslPolicy20170401S + cipher_suites: + - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + ca_certs_origin: + github_owner: gh-owner + github_repository: gh-repo + github_branch: gh-branch + github_directory: gh-dir + +rewrite_rule_sets: + - name: example-rewrite + rewrite_rules: + - name: example-rule + rule_sequence: 300 + conditions: + - variable: http_request_uri + pattern: '.*.html$' + ignore_case: true + negate: false + - variable: http_request_method + pattern: '^POST$' + ignore_case: true + negate: true + request_header_configurations: + - header_name: X-Rewrite-Rule + header_value: applied + response_header_configurations: + - header_name: X-Cache-Control + header_value: max-age=3600 + - header_name: X-Server + header_value: custom-app + url_rewrite: + source_path: '^/api/v1/(.*)' + components: path_only + reroute: false + +web_application_firewall_policy: + name: example-waf-policy + policy_settings: + enabled: true + mode: Detection + request_body_check: true + file_upload_limit_in_mb: 100 + max_request_body_size_in_kb: 128 + custom_rules: + - name: HeaderName + enabled: true + priority: 1 + rule_type: MatchRule + action: Allow + match_conditions: + - match_values: + - example.com + operator: Equal + match_variables: + - variable_name: RequestHeaders + selector: Host + - name: BlockUserAgentWindows + enabled: true + priority: 2 + rule_type: MatchRule + action: Block + match_conditions: + - operator: Contains + negation_condition: false + match_values: + - Windows + match_variables: + - variable_name: RequestHeaders + selector: UserAgent + managed_rule_set: + - type: OWASP + version: "3.2" + rule_group_override: + - rule_group_name: REQUEST-932-APPLICATION-ATTACK-RCE + rule: + - id: 932100 + action: AnomalyScoring + enabled: false + - id: 932110 + action: AnomalyScoring + enabled: false + +application_gateway: + name: example-appgw + identity: + type: UserAssigned + enable_http2: true + sku: + name: WAF_v2 + tier: WAF_v2 + capacity: 0 + gateway_ip_configuration: + name: appGatewayIpConfig + autoscale_configuration: + min_capacity: 0 + max_capacity: 10 + frontend_ports: + - name: port_80 + port: 80 + - name: port_443 + port: 443 + frontend_ip_configuration: + name: appGwPublicFrontendIpIPv4 + private_ip_address_allocation: Dynamic + ssl_certificates: + - name: example-cert-1 + key_vault_secret_id: https://example-kv.vault.azure.net/secrets/example-cert-1 \ No newline at end of file diff --git a/modules/azure-app-gateway/docs/footer.md b/modules/azure-app-gateway/docs/footer.md new file mode 100644 index 000000000..d4a68af7c --- /dev/null +++ b/modules/azure-app-gateway/docs/footer.md @@ -0,0 +1,17 @@ +--- + +## Examples + +For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/azure-app-gateway/_examples): + +- [basic](https://github.com/prefapp/tfm/tree/main/modules/azure-app-gateway/_examples/basic) - Application Gateway with public IP, WAF policy, SSL profiles and rewrite rules. + +## Recursos adicionales + +- [Azure Application Gateway](https://learn.microsoft.com/en-us/azure/application-gateway/overview) +- [Proveedor Terraform AzureRM](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/application_gateway) +- [Documentación oficial de Terraform](https://www.terraform.io/docs) + +## Soporte + +Para dudas, incidencias o contribuciones, utiliza el issue tracker del repositorio: [https://github.com/prefapp/tfm/issues](https://github.com/prefapp/tfm/issues) \ No newline at end of file diff --git a/modules/azure-app-gateway/docs/header.md b/modules/azure-app-gateway/docs/header.md new file mode 100644 index 000000000..fbb2cff8c --- /dev/null +++ b/modules/azure-app-gateway/docs/header.md @@ -0,0 +1,277 @@ +# Azure Application Gateway Terraform Module + +## Overview + +Este módulo de Terraform proporciona una solución flexible y productiva para desplegar y gestionar **Azure Application Gateway** en Azure. Permite la configuración avanzada de listeners, reglas de enrutamiento, certificados SSL, perfiles de seguridad, WAF y más, siguiendo buenas prácticas de infraestructura como código. + +El módulo está diseñado para adaptarse tanto a despliegues simples como complejos, permitiendo la integración con identidades gestionadas, políticas de seguridad, certificados desde Key Vault y reglas personalizadas de firewall. + +## Características principales + +- Provisionamiento completo de Application Gateway: frontend, backend, listeners, reglas, certificados y WAF. +- Soporte para perfiles SSL y certificados de cliente. +- Integración con Azure Key Vault para gestión segura de certificados. +- Reglas de reescritura y enrutamiento avanzadas. +- Web Application Firewall (WAF) configurable. +- Etiquetado flexible y herencia de etiquetas del Resource Group. + +## Estructura de archivos + +``` +. +├── main.tf +├── variables.tf +├── outputs.tf +├── versions.tf +├── data.tf +├── public_ip.tf +├── web_application_firewall_policy.tf +├── locals_*.tf +├── docs/ +│ ├── header.md +│ └── footer.md +├── CHANGELOG.md +├── README.md +└── .terraform-docs.yml +``` + +## Ejemplo completo de uso + +```yaml +values: + tags_from_rg: true + resource_group_name: ${{ tfworkspace:example-rg:outputs.resource_group_name }} + user_assigned_identity: "example-identity" + subnet: + name: "example-subnet" + virtual_network_name: "example-vnet" + public_ip: + name: "example-public-ip" + sku: "Standard" + allocation_method: "Static" + ssl_profiles: + - name: "example-ssl-profile" + verify_client_cert_issuer_dn: true + verify_client_certificate_revocation: "OCSP" + ssl_policy: + disabled_protocols: + - "TLSv1_0" + - "TLSv1_1" + min_protocol_version: "TLSv1_2" + policy_name: "AppGwSslPolicy20170401S" + cipher_suites: + - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" + - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" + ca_certs_origin: + github_owner: "gh-owner" + github_repository: "gh-repo" + github_branch: "gh-branch" + github_directory: "gh-dir" + rewrite_rule_sets: + - name: example-rewrite + rewrite_rules: + - name: example-rule + rule_sequence: 300 + conditions: + - variable: http_request_uri + pattern: '.*.html$' + ignore_case: true + negate: false + - variable: http_request_method + pattern: '^POST$' + ignore_case: true + negate: true + request_header_configurations: + - header_name: X-Rewrite-Rule + header_value: applied + response_header_configurations: + - header_name: X-Cache-Control + header_value: max-age=3600 + - header_name: X-Server + header_value: custom-app + url_rewrite: + source_path: '^/api/v1/(.*)' + components: path_only + reroute: false + web_application_firewall_policy: + name: "example-waf-policy" + policy_settings: + enabled: true + mode: "Detection" + request_body_check: true + file_upload_limit_in_mb: 100 + max_request_body_size_in_kb: 128 + custom_rules: + - name: "HeaderName" + enabled: true + priority: 1 + rule_type: "MatchRule" + action: "Allow" + match_conditions: + - match_values: + - "example.com" + operator: "Equal" + match_variables: + - variable_name: "RequestHeaders" + selector: "Host" + - name: "BlockUserAgentWindows" + enabled: true + priority: 2 + rule_type: "MatchRule" + action: "Block" + match_conditions: + - operator: "Contains" + negation_condition: false + match_values: + - "Windows" + match_variables: + - variable_name: "RequestHeaders" + selector: "UserAgent" + managed_rule_set: + - type: "OWASP" + version: "3.2" + rule_group_override: + - rule_group_name: "REQUEST-932-APPLICATION-ATTACK-RCE" + rule: + - id: "932100" + action: "AnomalyScoring" + enabled: false + - id: "932110" + action: "AnomalyScoring" + enabled: false + - rule_group_name: "REQUEST-942-APPLICATION-ATTACK-SQLI" + rule: + - id: "942430" + action: "AnomalyScoring" + enabled: false + - type: "Microsoft_BotManagerRuleSet" + version: "0.1" + application_gateway: + name: "example-appgw" + identity: + type: "UserAssigned" + enable_http2: true + sku: + name: "WAF_v2" + tier: "WAF_v2" + capacity: 0 + gateway_ip_configuration: + name: "appGatewayIpConfig" + autoscale_configuration: + min_capacity: 0 + max_capacity: 10 + frontend_ports: + - name: "port_80" + port: 80 + - name: "port_443" + port: 443 + frontend_ip_configuration: + name: "appGwPublicFrontendIpIPv4" + private_ip_address_allocation: "Dynamic" + ssl_certificates: + - name: "example-cert-1" + key_vault_secret_id: "https://example-kv.vault.azure.net/secrets/example-cert-1" + - name: "example-cert-2" + key_vault_secret_id: "https://example-kv.vault.azure.net/secrets/example-cert-2" + blocks_defaults: + backend_http_settings: + cookie_based_affinity: "Disabled" + pick_host_name_from_backend_address: false + port: 80 + protocol: "Http" + request_timeout: 20 + trusted_root_certificate_names: [] + http_listeners: + https: + frontend_ip_configuration_name: "appGwPublicFrontendIpIPv4" + frontend_port_name: "port_443" + protocol: "Https" + ssl_certificate_name: "example-cert-2" + ssl_profile_name: "example-ssl-profile" + http-redirection: + frontend_ip_configuration_name: "appGwPublicFrontendIpIPv4" + frontend_port_name: "port_80" + protocol: "Http" + require_sni: false + probe: + host: "10.0.0.1" + interval: 10 + minimum_servers: 0 + path: "/" + pick_host_name_from_backend_http_settings: false + protocol: "Http" + timeout: 30 + unhealthy_threshold: 3 + matches: + - status_code: ["200-399", "404"] + redirect_configuration: + include_path: true + include_query_string: true + redirect_type: "Permanent" + request_routing_rules: + http-redirection: + rule_type: "Basic" + rewrite_rule_set_name: example-rewrite + https: + rule_type: "Basic" + rewrite_rule_set_name: example-rewrite + blocks: + organization1: + app1: + pro: + backend_http_settings: + request_timeout: 90 + redirect_configuration: {} + backend_address_pool: + ip_addresses: + - 10.0.0.2 + http_listeners: + https: + host_names: + - "example.com" + ssl_certificate_name: "example-cert-1" + http-redirection: + host_names: + - "example.com" + probe: + host: "10.0.0.2" + request_routing_rules: + http-redirection: + priority: 10 + name: "redirect-example" + redirect_configuration_name: "redirect-example" + https: + backend_address_pool_name: "backend_address_pool-example" + backend_http_settings_name: "backend_http_settings-example" + priority: 11 + name: "request_routing_rule-example" + organization2: + app1: + pro: + backend_http_settings: + request_timeout: 60 + redirect_configuration: {} + backend_address_pool: + ip_addresses: + - 10.0.0.3 + http_listeners: + https: + host_names: + - "another-example.com" + ssl_certificate_name: "example-cert-1" + http-redirection: + host_names: + - "another-example.com" + probe: + host: "10.0.0.3" + request_routing_rules: + http-redirection: + priority: 20 + name: "redirect-another-example" + redirect_configuration_name: "redirect-another-example" + https: + backend_address_pool_name: "backend_address_pool-another-example" + backend_http_settings_name: "backend_http_settings-another-example" + priority: 21 + name: "request_routing_rule-another-example" +``` \ No newline at end of file