diff --git a/terraform/deployments/govuk-publishing-infrastructure/search_api_gateway.tf b/terraform/deployments/govuk-publishing-infrastructure/search_api_gateway.tf index 9420d1164..c6da4a14b 100644 --- a/terraform/deployments/govuk-publishing-infrastructure/search_api_gateway.tf +++ b/terraform/deployments/govuk-publishing-infrastructure/search_api_gateway.tf @@ -1,3 +1,8 @@ +resource "aws_api_gateway_domain_name" "search_api_domain" { + domain_name = var.search_api_domain + certificate_arn = var.publishing_certificate_arn +} + # VPC Link to allow API Gateway to connect to the search load balancer resource "aws_api_gateway_vpc_link" "search_vpc_link" { name = "search_api_vpc_link" @@ -11,7 +16,7 @@ resource "aws_api_gateway_rest_api" "search_rest_api" { description = "API Gateway for Search API" endpoint_configuration { - types = ["EDGE"] # "Edge-optimized" routes traffic through CloudFront + types = ["EDGE"] # "Edge-optimized" routes traffic through CloudFront } } @@ -46,6 +51,61 @@ resource "aws_api_gateway_deployment" "search_deployment" { stage_name = "v0.1" # Version embedded in the published URL } +# Map API Gateway stages to custom domain +resource "aws_api_gateway_base_path_mapping" "search_api_mapping" { + domain_name = aws_api_gateway_domain_name.search_api_domain.domain_name + api_id = aws_api_gateway_rest_api.search_api.id +} + +# WAF settings +resource "aws_wafv2_web_acl" "search_api_waf" { + name = "search-api-waf" + description = "WAF for Search API with rate limiting" + scope = "CLOUDFRONT" + + default_action { + allow {} + } + + rule { + name = "rate-limit-rule" + priority = 1 + action { + block {} + } + + statement { + rate_based_statement { + limit = 100 # Limit 100 requests per IP in 5 minutes + aggregate_key_type = "IP" + } + } + + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "search-api-rate-limit-rule" + sampled_requests_enabled = true + } + } + + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "search-api-waf" + sampled_requests_enabled = true + } +} + +resource "aws_wafv2_web_acl_association" "waf_association" { + resource_arn = aws_api_gateway_domain_name.search_api_domain.cloudfront_domain_name + web_acl_arn = aws_wafv2_web_acl.search_api_waf.arn +} + +resource "aws_shield_protection" "search_api_shield" { + name = "search-api-shield" + resource_arn = aws_api_gateway_rest_api.search_api.execution_arn +} + + output "api_gateway_cname" { value = aws_api_gateway_domain_name.search_api_domain.cloudfront_domain_name description = "CNAME to use in your DNS settings" diff --git a/terraform/deployments/govuk-publishing-infrastructure/variables.tf b/terraform/deployments/govuk-publishing-infrastructure/variables.tf index 9bb5ac1d1..692d32781 100644 --- a/terraform/deployments/govuk-publishing-infrastructure/variables.tf +++ b/terraform/deployments/govuk-publishing-infrastructure/variables.tf @@ -62,3 +62,13 @@ variable "search_api_lb_dns_name" { type = string description = "The DNS name of the search-api-v2 load balancer" } + +variable "search_api_domain" { + type = string + description = "The domain name of the API gateway" +} + +variable "publishing_certificate_arn" { + type = string + description = "The ARN of the publishing certificate" +}