API Gateway V2与ALB私有集成持续返回503故障排查求助
问题排查:API Gateway V2与ALB私有集成无流量到达ALB
问题背景
已通过Terraform完成API Gateway V2与内部Application Load Balancer(ALB)的VPC Link私有集成部署,所有资源状态显示正常:
- VPC Link状态正常
- ALB目标组健康检查通过
- 自定义Lambda授权器返回正确响应(API Gateway日志可佐证)
- API Gateway的路由、授权器、集成配置关联无误
但请求始终无法到达ALB:S3中无ALB访问日志/连接日志,VPC流日志也未记录进入ALB的流量。
配置代码
resource "aws_apigatewayv2_vpc_link" "alb_connection" { name = "${local.full_name}-vpc-link" security_group_ids = [aws_security_group.alb_sg.id] subnet_ids = data.aws_subnets.web.ids tags = module.network_label.tags } resource "aws_cognito_resource_server" "alb_connection" { identifier = "${var.environment}.${var.area}.${var.application}" name = "${var.environment}-${local.full_name}-rs" dynamic "scope" { for_each = var.scopes content { scope_name = scope.value scope_description = "Allow ${scope.value} access to ${local.full_name}/${var.area}" } } user_pool_id = one(data.aws_cognito_user_pools.selected.ids) } resource "aws_apigatewayv2_authorizer" "alb_connection" { name = "http-api-request-authorizer" api_id = data.aws_apigatewayv2_api.gateway.id authorizer_type = "REQUEST" identity_sources = ["$request.header.Authorization"] authorizer_uri = data.aws_lambda_function.authorizer.invoke_arn enable_simple_responses = true authorizer_payload_format_version = "2.0" } resource "aws_apigatewayv2_route" "alb_connection" { api_id = data.aws_apigatewayv2_api.gateway.id route_key = "ANY /${var.area}/{proxy+}" target = "integrations/${aws_apigatewayv2_integration.alb_connection.id}" authorizer_id = aws_apigatewayv2_authorizer.alb_connection.id authorization_type = "CUSTOM" # authorization_scopes = ["${aws_cognito_resource_server.alb_connection.identifier}/${each.value}"] } resource "aws_apigatewayv2_integration" "alb_connection" { api_id = data.aws_apigatewayv2_api.gateway.id description = "Integration connecting ${var.api_gateway_name} to ${local.full_name}" integration_type = "HTTP_PROXY" integration_uri = aws_lb_listener.this.arn payload_format_version = "1.0" # Required for HTTP_PROXY integrations (private integrations) integration_method = "ANY" connection_type = "VPC_LINK" connection_id = aws_apigatewayv2_vpc_link.alb_connection.id request_parameters = { "append:header.authforintegration" = "$context.authorizer.authorizerResponse" } response_parameters { status_code = 403 mappings = { "append:header.auth" = "$context.authorizer.authorizerResponse" } } } resource "aws_lb" "alb" { # Set the basic fields of the load balancer name = "${local.full_name}-alb-${random_string.id.result}" internal = true load_balancer_type = "application" enable_deletion_protection = false security_groups = [aws_security_group.alb_sg.id] subnets = data.aws_subnets.web.ids # Setup logging for access access_logs { bucket = data.aws_s3_bucket.audit.id prefix = local.full_path enabled = true } # Setup connection logs connection_logs { bucket = data.aws_s3_bucket.audit.id prefix = local.full_path enabled = true } tags = module.alb_group_label.tags # Ensure a new instance of this load balancer is created before the old one is destroyed to avoid downtime lifecycle { create_before_destroy = true } } resource "aws_s3_bucket_policy" "allow_log_access" { bucket = data.aws_s3_bucket.audit.id policy = data.aws_iam_policy_document.alb_access_policy.json } resource "aws_lb_target_group" "target_group" { name = "${local.full_name}-tg-${random_string.id.result}" target_type = "ip" protocol = "HTTP" port = var.service_port vpc_id = data.aws_vpc.main.id tags = module.alb_group_label.tags slow_start = var.slow_start health_check { enabled = true port = var.service_port interval = 30 timeout = 5 protocol = "HTTP" path = var.health_check matcher = "200" healthy_threshold = 3 unhealthy_threshold = 3 } # Ensure a new instance of this target group is created before the old one is destroyed to avoid downtime lifecycle { create_before_destroy = true } } resource "aws_lb_listener" "this" { load_balancer_arn = aws_lb.alb.arn port = 443 protocol = "HTTPS" ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06" certificate_arn = aws_acm_certificate.ssl_certificate.arn default_action { type = "forward" target_group_arn = aws_lb_target_group.target_group.arn } tags = module.alb_group_label.tags # Need to ensure that the listener is destroyed before the target group or we won't be able to destroy the target # group at all. lifecycle { create_before_destroy = true replace_triggered_by = [ aws_lb_target_group.target_group ] } }
可能的原因及解决方法
1. ALB安全组入站规则未放通API Gateway流量
API Gateway通过VPC Link访问ALB时,使用对应区域的execute-api服务IP段。需检查aws_security_group.alb_sg的入站规则:
- 添加HTTPS(443端口)的入站规则,来源设置为当前区域的
com.amazonaws.<region>.execute-api前缀列表(可通过aws ec2 describe-prefix-lists --region <你的区域>获取前缀列表ID,格式为pl-xxxxxx)
2. API Gateway集成的Host头不匹配ALB证书域名
API Gateway默认会将自身域名作为Host头转发给ALB,如果ALB的ACM证书未覆盖该域名,会导致TLS握手失败,流量被丢弃。
修改集成配置,强制设置Host头为ALB的DNS名称:
resource "aws_apigatewayv2_integration" "alb_connection" { # ... 其他配置保持不变 request_parameters = { "overwrite:header.Host" = aws_lb.alb.dns_name "append:header.authforintegration" = "$context.authorizer.authorizerResponse" } }
3. 路由路径匹配失败
确认请求路径严格匹配路由规则ANY /${var.area}/{proxy+}:
- 例如
var.area为api时,请求路径需为/api/xxx格式 - 查看API Gateway执行日志,确认请求是否命中目标路由
4. VPC Link子网配置异常
- 确认VPC Link关联的子网
data.aws_subnets.web.ids与ALB子网属于同一VPC - 检查子网路由表,确保允许同VPC内的流量互通(默认允许,自定义路由表需验证)
- 确认子网有足够的可用IP,VPC Link需要在每个子网创建ENI用于流量转发
5. 授权器实际未通过验证
虽然授权器返回响应,需确认其返回的isAuthorized字段为true:
- 查看API Gateway日志中的授权阶段结果,若
isAuthorized为false,API Gateway会直接返回403,不会转发流量到ALB
内容的提问来源于stack exchange,提问作者Woody1193
相关产品推荐
相关产品推荐

