You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在AWS WAF/ALB中自动插入源IP的GeoIP地域至自定义请求头?

解决方案:将请求源IP的GeoIP地域信息插入自定义请求头

首先明确:AWS WAF v2的custom_request_handling中的insert_header确实仅支持静态字符串值,无法直接引用GeoIP这类动态变量,你提供的Terraform配置写法无法实现需求。以下是两种可行的实现方式:

方案1:CloudFront + Lambda@Edge(适用于使用CloudFront作为CDN的场景)

CloudFront内置了请求源IP的GeoIP信息,可以通过Lambda@Edge在Viewer Request阶段获取这些信息,并插入自定义请求头后转发到后端。

Terraform配置示例

  1. 编写Lambda函数代码(用于插入GeoIP头):
def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    # 从CloudFront内置变量中获取国家代码
    country_code = request['headers'].get('cloudfront-viewer-country', [{'value': 'UNKNOWN'}])[0]['value']
    # 插入自定义请求头
    request['headers']['x-country-code'] = [{'key': 'X-Country-Code', 'value': country_code}]
    return request
  1. Terraform配置Lambda@Edge和CloudFront:
# 创建Lambda函数(需部署在us-east-1区域)
resource "aws_lambda_function" "geoip_header_insert" {
  filename      = "geoip-handler.zip"
  function_name = "GeoIP-Header-Insert"
  role          = aws_iam_role.lambda_edge_role.arn
  handler       = "index.lambda_handler"
  runtime       = "python3.12"
  source_code_hash = filebase64sha256("geoip-handler.zip")
  publish       = true # 必须发布版本才能用于Lambda@Edge
}

# Lambda@Edge所需的IAM角色
resource "aws_iam_role" "lambda_edge_role" {
  name = "Lambda-Edge-GeoIP-Role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = ["lambda.amazonaws.com", "edgelambda.amazonaws.com"]
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_edge_basic_execution" {
  role       = aws_iam_role.lambda_edge_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

# CloudFront分发配置,关联Lambda@Edge
resource "aws_cloudfront_distribution" "my_distribution" {
  # 其他CloudFront基础配置(略)

  default_cache_behavior {
    # 其他缓存行为配置(略)

    lambda_function_association {
      event_type   = "viewer-request"
      lambda_arn   = "${aws_lambda_function.geoip_header_insert.arn}:${aws_lambda_function.geoip_header_insert.version}"
      include_body = false
    }
  }
}

方案2:ALB + Lambda函数(适用于直接使用ALB暴露服务的场景)

ALB本身不支持直接插入GeoIP信息,但可以通过Lambda函数集成,在请求到达目标组前处理并插入自定义头。

Terraform配置示例

  1. Lambda函数代码(需引入GeoIP库,如maxminddb,或调用AWS Location服务获取IP地理信息):
import maxminddb
import os

# 假设已将GeoIP数据库打包到Lambda部署包中
GEOIP_DB_PATH = os.path.join(os.path.dirname(__file__), 'GeoLite2-Country.mmdb')

def lambda_handler(event, context):
    # 获取请求源IP
    source_ip = event['requestContext']['elb']['sourceIp']
    # 查询GeoIP信息
    with maxminddb.open_database(GEOIP_DB_PATH) as reader:
        try:
            response = reader.get(source_ip)
            country_code = response['country']['iso_code'] if response else 'UNKNOWN'
        except:
            country_code = 'UNKNOWN'
    # 修改请求头
    event['headers']['x-country-code'] = country_code
    # 返回修改后的请求,转发到目标组
    return {
        'statusCode': 200,
        'headers': event['headers'],
        'body': event['body'],
        'isBase64Encoded': event['isBase64Encoded']
    }
  1. Terraform配置ALB与Lambda集成:
# 创建Lambda函数
resource "aws_lambda_function" "geoip_header_insert_alb" {
  filename      = "geoip-alb-handler.zip"
  function_name = "GeoIP-ALB-Header-Insert"
  role          = aws_iam_role.alb_lambda_role.arn
  handler       = "index.lambda_handler"
  runtime       = "python3.12"
  source_code_hash = filebase64sha256("geoip-alb-handler.zip")
}

# ALB Lambda集成所需IAM角色
resource "aws_iam_role" "alb_lambda_role" {
  name = "ALB-Lambda-GeoIP-Role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "alb_lambda_basic_execution" {
  role       = aws_iam_role.alb_lambda_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

# 允许ALB调用Lambda
resource "aws_lambda_permission" "alb_invoke_lambda" {
  statement_id  = "AllowALBInvoke"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.geoip_header_insert_alb.function_name
  principal     = "elasticloadbalancing.amazonaws.com"
  source_arn    = aws_lb_target_group.my_target_group.arn
}

# 配置Lambda类型的目标组
resource "aws_lb_target_group" "my_target_group" {
  name     = "geoip-target-group"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.my_vpc.id

  target_type = "lambda"
  lambda_function {
    arn = aws_lambda_function.geoip_header_insert_alb.arn
  }
}

# ALB监听器指向该目标组
resource "aws_lb_listener" "my_listener" {
  load_balancer_arn = aws_lb.my_alb.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.my_target_group.arn
  }
}

注意:方案2中使用的GeoIP数据库需自行下载(如MaxMind的GeoLite2)并打包到Lambda部署包中,也可改用AWS Location Service的IP地理定位API获取信息。

内容的提问来源于stack exchange,提问作者Orabïg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 03:50:08