api-gateway.tf 3.58 KB
# VPC Link for connecting API Gateway to NLB
resource "aws_apigatewayv2_vpc_link" "user_management" {
  name               = "${var.api_gateway_name}-vpc-link"
  security_group_ids = [aws_security_group.vpc_link.id]
  subnet_ids         = data.aws_subnets.private.ids

  tags = merge(var.tags, {
    Name        = "${var.api_gateway_name}-vpc-link"
    Environment = var.environment
    Project     = "user-management"
  })
}

# HTTP API Gateway
resource "aws_apigatewayv2_api" "user_management" {
  name          = var.api_gateway_name
  protocol_type = "HTTP"
  description   = "User Management System HTTP API"
  
  # CORS 配置 - 允许所有来源(生产环境应限制)
  cors_configuration {
    allow_origins = ["*"]
    allow_methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
    allow_headers = ["*"]
    max_age       = 300
  }

  tags = merge(var.tags, {
    Name        = var.api_gateway_name
    Environment = var.environment
    Project     = "user-management"
  })
}

# Integration with NLB via VPC Link
resource "aws_apigatewayv2_integration" "user_management" {
  api_id             = aws_apigatewayv2_api.user_management.id
  integration_type   = "HTTP_PROXY"
  integration_method = "ANY"
  integration_uri    = "http://${data.aws_lb.nlb.dns_name}"

  connection_type    = "VPC_LINK"
  connection_id      = aws_apigatewayv2_vpc_link.user_management.id

  # 传递所有请求参数
  request_parameters = {
    "overwrite:path" = "/$request.path.proxy"
  }

  depends_on = [data.aws_lb.nlb]
}

# 定义路由
locals {
  routes = {
    "root"        = "GET /"
    "api"         = "GET /api"
    "health"      = "GET /api/health"
    "users"       = "ANY /api/users"
    "user_detail" = "ANY /api/users/{id}"
    "catch_all"   = "ANY /{proxy+}"
  }
}

resource "aws_apigatewayv2_route" "routes" {
  for_each = local.routes

  api_id    = aws_apigatewayv2_api.user_management.id
  route_key = each.value
  target    = "integrations/${aws_apigatewayv2_integration.user_management.id}"

  # 为 OPTIONS 请求自动处理 CORS
  dynamic "cors_configuration" {
    for_each = each.key == "catch_all" ? [] : [1]
    content {
      allow_origins = ["*"]
      allow_methods = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
      allow_headers = ["*"]
      max_age       = 300
    }
  }
}

# Production Stage
resource "aws_apigatewayv2_stage" "production" {
  api_id      = aws_apigatewayv2_api.user_management.id
  name        = var.environment
  auto_deploy = true

  # Access Logs
  access_log_settings {
    destination_arn = aws_cloudwatch_log_group.api_gateway.arn
    format = jsonencode({
      requestId               = "$context.requestId"
      sourceIp                = "$context.identity.sourceIp"
      requestTime             = "$context.requestTime"
      protocol                = "$context.protocol"
      httpMethod              = "$context.httpMethod"
      resourcePath            = "$context.resourcePath"
      routeKey                = "$context.routeKey"
      status                  = "$context.status"
      responseLength          = "$context.responseLength"
      integrationErrorMessage = "$context.integrationErrorMessage"
    })
  }

  tags = merge(var.tags, {
    Name        = "${var.api_gateway_name}-${var.environment}"
    Environment = var.environment
    Project     = "user-management"
  })
}

# CloudWatch Log Group
resource "aws_cloudwatch_log_group" "api_gateway" {
  name              = "/aws/apigateway/${var.api_gateway_name}"
  retention_in_days = 30

  tags = merge(var.tags, {
    Name        = "${var.api_gateway_name}-logs"
    Environment = var.environment
    Project     = "user-management"
  })
}