Envoy IP 标签(IP Tagging)功能实现分析

1. 概述

Envoy 的 IP 标签(IP Tagging)功能是一个强大而灵活的流量分类工具,提供了基于源 IP 地址的标签匹配和头部添加功能。它通过使用高效的 LC-Trie 算法实现快速的 IP 地址匹配,并提供了详细的统计信息,帮助监控和识别流量模式。

它通过将源 IP 地址与预配置的 CIDR 范围进行匹配,为匹配成功的请求添加 x-envoy-ip-tags 头部,包含匹配到的标签。

通过使用 IP 标签功能,您可以:

  1. 为请求添加标签,便于日志记录和统计分析

  2. 与其他过滤器配合使用,提供更精细的访问控制

  3. 简化基于源 IP 地址的策略配置

  4. 支持运行时配置,可动态启用/禁用功能

  5. 提供详细的统计信息,帮助监控和识别流量模式

该功能在微服务架构中特别重要,可以帮助您管理多个服务的访问控制,确保只有授权的用户和服务能够访问受保护的资源,并为流量分析和监控提供有价值的信息。

2. 解决的问题

IP 标签功能主要解决以下问题:

2.1 流量分类与识别

  • 允许对流量进行基于源 IP 地址的分类

  • 为内部和外部流量提供不同的标签

  • 帮助识别来自特定区域或网络的请求

2.2 访问控制优化

  • 可以与其他过滤器(如 RBAC)配合使用,提供更精细的访问控制

  • 基于标签实现复杂的路由和限流策略

  • 简化基于源 IP 地址的策略配置

2.3 流量分析与监控

  • 为请求添加标签,便于日志记录和统计分析

  • 提供详细的统计信息,帮助监控和识别流量模式

  • 支持基于标签的指标收集和报警

2.4 性能优化

  • 使用 LC-Trie(最长前缀匹配)算法实现高效的 IP 地址匹配

  • 支持运行时配置,可动态启用/禁用功能

  • 与其他 Envoy 过滤器集成良好

3. 架构设计

3.1 核心组件架构

3.2 类图

3. 配置用例

3.1 基础配置

bash 复制代码
http_filters:- name: envoy.filters.http.ip_tagging  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.ip_tagging.v3.IPTagging    request_type: BOTH    ip_tags:    - ip_tag_name: "internal"      ip_list:      - address_prefix: "10.0.0.0"        prefix_len: 8      - address_prefix: "172.16.0.0"        prefix_len: 12      - address_prefix: "192.168.0.0"        prefix_len: 16    - ip_tag_name: "test"      ip_list:      - address_prefix: "10.10.0.0"        prefix_len: 16    - ip_tag_name: "production"      ip_list:      - address_prefix: "52.100.0.0"        prefix_len: 16

3.2 运行时配置

javascript 复制代码
layered_runtime:  layers:  - name: static_layer    static_layer:      ip_tagging:        http_filter_enabled: true

3.3 高级配置

bash 复制代码
http_filters:- name: envoy.filters.http.ip_tagging  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.ip_tagging.v3.IPTagging    request_type: EXTERNAL    ip_tags:    - ip_tag_name: "eu-west-1"      ip_list:      - address_prefix: "34.240.0.0"        prefix_len: 12      - address_prefix: "52.17.0.0"        prefix_len: 16    - ip_tag_name: "us-east-1"      ip_list:      - address_prefix: "3.208.0.0"        prefix_len: 12      - address_prefix: "52.95.0.0"        prefix_len: 16    - ip_tag_name: "ap-southeast-1"      ip_list:      - address_prefix: "13.250.0.0"        prefix_len: 12      - address_prefix: "18.139.0.0"        prefix_len: 16

3.4 与其他过滤器配合使用

bash 复制代码
http_filters:- name: envoy.filters.http.ip_tagging  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.ip_tagging.v3.IPTagging    request_type: BOTH    ip_tags:    - ip_tag_name: "internal"      ip_list:      - address_prefix: "10.0.0.0"        prefix_len: 8    - ip_tag_name: "external"      ip_list:      - address_prefix: "0.0.0.0"        prefix_len: 0
- name: envoy.filters.http.rbac  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC    rules:      action: ALLOW      policies:        "internal_access":          permissions:          - or_rules:              rules:              - url_path_match:                  path: "/internal/*"          principals:          - request_header_match:              name: "x-envoy-ip-tags"              value: "internal"

4. 工作流程分析

4.1 过滤器执行流程

4.2 IP 标签匹配流程

5. 代码实现ER图

6. 最佳实践

6.1 标签设计原则

bash 复制代码
# 使用有意义的标签名称http_filters:- name: envoy.filters.http.ip_tagging  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.ip_tagging.v3.IPTagging    request_type: BOTH    ip_tags:    - ip_tag_name: "eu-west-1"      ip_list:      - address_prefix: "34.240.0.0"        prefix_len: 12    - ip_tag_name: "us-east-1"      ip_list:      - address_prefix: "3.208.0.0"        prefix_len: 12    - ip_tag_name: "ap-southeast-1"      ip_list:      - address_prefix: "13.250.0.0"        prefix_len: 12

6.2 与其他过滤器配合使用

bash 复制代码
# 使用标签进行访问控制http_filters:- name: envoy.filters.http.ip_tagging  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.ip_tagging.v3.IPTagging    request_type: BOTH    ip_tags:    - ip_tag_name: "internal"      ip_list:      - address_prefix: "10.0.0.0"        prefix_len: 8    - ip_tag_name: "external"      ip_list:      - address_prefix: "0.0.0.0"        prefix_len: 0
- name: envoy.filters.http.rbac  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC    rules:      action: ALLOW      policies:        "internal_access":          permissions:          - or_rules:              rules:              - url_path_match:                  path: "/internal/*"          principals:          - request_header_match:              name: "x-envoy-ip-tags"              value: "internal"

6.3 性能优化

bash 复制代码
# 使用最小权限原则http_filters:- name: envoy.filters.http.ip_tagging  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.ip_tagging.v3.IPTagging    request_type: EXTERNAL    ip_tags:    - ip_tag_name: "trusted"      ip_list:      - address_prefix: "192.168.0.0"        prefix_len: 16      - address_prefix: "10.0.0.0"        prefix_len: 8    - ip_tag_name: "untrusted"      ip_list:      - address_prefix: "0.0.0.0"        prefix_len: 0

6.4 运行时配置

bash 复制代码
# 使用运行时配置动态启用/禁用功能http_filters:- name: envoy.filters.http.ip_tagging  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.ip_tagging.v3.IPTagging    request_type: BOTH    ip_tags:    - ip_tag_name: "internal"      ip_list:      - address_prefix: "10.0.0.0"        prefix_len: 8
layered_runtime:  layers:  - name: static_layer    static_layer:      ip_tagging:        http_filter_enabled: true

7. 代码实现细节

7.1 过滤器初始化

php 复制代码
IpTaggingFilterConfig::IpTaggingFilterConfig(    const envoy::extensions::filters::http::ip_tagging::v3::IPTagging& config,    const std::string& stat_prefix, Stats::Scope& scope, Runtime::Loader& runtime)    : request_type_(requestTypeEnum(config.request_type())), scope_(scope), runtime_(runtime),      stat_name_set_(scope.symbolTable().makeSet("IpTagging")),      stats_prefix_(stat_name_set_->add(stat_prefix + "ip_tagging")),      no_hit_(stat_name_set_->add("no_hit")), total_(stat_name_set_->add("total")),      unknown_tag_(stat_name_set_->add("unknown_tag.hit")) {
  // 检查是否配置了 IP 标签  if (config.ip_tags().empty()) {    throw EnvoyException("HTTP IP Tagging Filter requires ip_tags to be specified.");  }
  // 构建标签数据结构  std::vector<std::pair<std::string, std::vector<Network::Address::CidrRange>>> tag_data;  tag_data.reserve(config.ip_tags().size());
  for (const auto& ip_tag : config.ip_tags()) {    std::vector<Network::Address::CidrRange> cidr_set;    cidr_set.reserve(ip_tag.ip_list().size());
    for (const envoy::config::core::v3::CidrRange& entry : ip_tag.ip_list()) {      Network::Address::CidrRange cidr_entry = Network::Address::CidrRange::create(entry);      if (cidr_entry.isValid()) {        cidr_set.emplace_back(std::move(cidr_entry));      } else {        throw EnvoyException(            fmt::format("invalid ip/mask combo '{}/{}' (format is <ip>/<# mask bits>)",                        entry.address_prefix(), entry.prefix_len().value()));      }    }
    tag_data.emplace_back(ip_tag.ip_tag_name(), cidr_set);    stat_name_set_->rememberBuiltin(absl::StrCat(ip_tag.ip_tag_name(), ".hit"));  }
  // 创建 LC-Trie 用于快速 IP 地址匹配  trie_ = std::make_unique<Network::LcTrie::LcTrie<std::string>>(tag_data);}

7.2 标签匹配逻辑

php 复制代码
Http::FilterHeadersStatusIpTaggingFilter::decodeHeaders(Http::RequestHeaderMap& headers, bool) {  const bool is_internal_request = headers.EnvoyInternalRequest() &&                                   (headers.EnvoyInternalRequest()->value() ==                                    Http::Headers::get().EnvoyInternalRequestValues.True.c_str());
  // 检查是否应该应用过滤器  if ((is_internal_request && config_->requestType() == FilterRequestType::EXTERNAL) ||      (!is_internal_request && config_->requestType() == FilterRequestType::INTERNAL) ||      !config_->runtime().snapshot().featureEnabled("ip_tagging.http_filter_enabled", 100)) {    return Http::FilterHeadersStatus::Continue;  }
  // 匹配 IP 地址到标签  std::vector<std::string> tags =      config_->trie().getData(callbacks_->streamInfo().downstreamAddressProvider().remoteAddress());
  if (!tags.empty()) {    const std::string tags_join = absl::StrJoin(tags, ",");    headers.appendEnvoyIpTags(tags_join, ",");
    // 清除路由缓存,以便后续可以匹配到 x-envoy-ip-tags 头部    callbacks_->clearRouteCache();
    // 记录匹配到的标签统计    for (const std::string& tag : tags) {      config_->incHit(tag);    }  } else {    config_->incNoHit();  }
  config_->incTotal();  return Http::FilterHeadersStatus::Continue;}

7.3 统计信息更新

css 复制代码
void IpTaggingFilterConfig::incCounter(Stats::StatName name) {  Stats::SymbolTable::StoragePtr storage = scope_.symbolTable().join({stats_prefix_, name});  scope_.counterFromStatName(Stats::StatName(storage.get())).inc();}
void IpTaggingFilterConfig::incHit(absl::string_view tag) {  incCounter(stat_name_set_->getBuiltin(absl::StrCat(tag, ".hit"), unknown_tag_));}
void IpTaggingFilterConfig::incNoHit() {  incCounter(no_hit_);}
void IpTaggingFilterConfig::incTotal() {  incCounter(total_);}
相关推荐
NJCloud5 分钟前
Docker 私有仓库部署:Registry、加密传输与认证鉴权
运维·网络·docker·云原生·容器
CC城子21 分钟前
Bootloader + OTA -Ymodem 协议
网络·ymoden
又见情义28 分钟前
RK3568 + RTL8211F 网络唤醒(WOL)功能适配全记录
android·网络·驱动开发
Titan202442 分钟前
HTTPS基础知识梳理
服务器·网络·c++·网络协议·学习·http·https
自然石人1 小时前
石都随笔:深耕不张扬,平凡自有千钧力
网络·经验分享·百度·传媒·新浪微博
新时代牛马1 小时前
epoll 源码路径:从epoll_ctl 到ep_poll 的就绪唤醒
网络·数据库·网络协议
简单Janeee1 小时前
[Vue 3 从零到上线]-第九篇:更美更强——引入 UI 库与网络请求 (Axios)
网络·vue.js·ui
学习星球1 小时前
空天地一体化网络(NTN)深度解析:从Starlink D2C到3GPP NTN,卫星直连手机是如何实现的?
网络·人工智能·算法·智能手机·php
艾莉丝努力练剑2 小时前
【AI大模型接入SDK】WebSocket & SSE 协议
网络·c++·websocket·网络协议·学习·面试
xieliyu.2 小时前
计算机网络‑IP 协议解析:核心特性总结
网络·笔记·网络协议·学习·tcp/ip·计算机网络