diff --git a/terraform/deployments/govuk-publishing-infrastructure/variables.tf b/terraform/deployments/govuk-publishing-infrastructure/variables.tf index 7c3a09961..2b7a5d300 100644 --- a/terraform/deployments/govuk-publishing-infrastructure/variables.tf +++ b/terraform/deployments/govuk-publishing-infrastructure/variables.tf @@ -64,6 +64,11 @@ variable "search_api_domain" { description = "The domain name of the API gateway" } +variable "publishing_service_domain" { + type = string + description = "FQDN of the user-facing domain for the publishing apps, e.g. staging.publishing.service.gov.uk. This domain is included as a wildcard SAN on the TLS cert for Ingresses etc." +} + variable "publishing_certificate_arn" { type = string description = "The ARN of the publishing certificate" @@ -139,6 +144,12 @@ variable "backend_public_base_rate_limit" { default = 1000 } +variable "chat_domain_base_rate_limit" { + type = number + description = "An enforced rate limit threshold for the chat domain" + default = 75000 +} + variable "backend_public_ja3_denylist" { type = list(string) description = "For the backend ALB. List of JA3 signatures for which we should block all requests." diff --git a/terraform/deployments/govuk-publishing-infrastructure/wafs.tf b/terraform/deployments/govuk-publishing-infrastructure/wafs.tf index f7ff846f7..e98996f6f 100644 --- a/terraform/deployments/govuk-publishing-infrastructure/wafs.tf +++ b/terraform/deployments/govuk-publishing-infrastructure/wafs.tf @@ -217,6 +217,90 @@ resource "aws_wafv2_web_acl" "backend_public" { } } + rule { + name = "chat-domain-rate-limit" + priority = 25 + + action { + block { + custom_response { + response_code = 429 + + response_header { + name = "Retry-After" + value = 30 + } + + response_header { + name = "Cache-Control" + value = "max-age=0, private" + } + + custom_response_body_key = "backend-public-rule-429" + } + } + } + + statement { + rate_based_statement { + limit = var.chat_domain_base_rate_limit + aggregate_key_type = "IP" + + scope_down_statement { + byte_match_statement { + search_string = "chat.${var.publishing_service_domain}" + field_to_match { + single_header { + name = "host" + } + } + positional_constraint = "EXACTLY" + text_transformation { + priority = 0 + type = "LOWERCASE" + } + } + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "chat-domain-rate-limit" + sampled_requests_enabled = true + } + } + + rule { + name = "chat-domain-allow" + priority = 26 + + action { + allow {} + } + + statement { + byte_match_statement { + search_string = "chat.${var.publishing_service_domain}" + field_to_match { + single_header { + name = "host" + } + } + positional_constraint = "EXACTLY" + text_transformation { + priority = 0 + type = "LOWERCASE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "chat-domain-allow" + sampled_requests_enabled = true + } + } # This rule is intended for monitoring only # set a base rate limit per IP looking back over the last 5 minutes # this is checked every 30s