1. 概述
Envoy 的 IP 标签(IP Tagging)功能是一个强大而灵活的流量分类工具,提供了基于源 IP 地址的标签匹配和头部添加功能。它通过使用高效的 LC-Trie 算法实现快速的 IP 地址匹配,并提供了详细的统计信息,帮助监控和识别流量模式。
它通过将源 IP 地址与预配置的 CIDR 范围进行匹配,为匹配成功的请求添加 x-envoy-ip-tags 头部,包含匹配到的标签。
通过使用 IP 标签功能,您可以:
-
为请求添加标签,便于日志记录和统计分析
-
与其他过滤器配合使用,提供更精细的访问控制
-
简化基于源 IP 地址的策略配置
-
支持运行时配置,可动态启用/禁用功能
-
提供详细的统计信息,帮助监控和识别流量模式
该功能在微服务架构中特别重要,可以帮助您管理多个服务的访问控制,确保只有授权的用户和服务能够访问受保护的资源,并为流量分析和监控提供有价值的信息。
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_);}