优化 GCP Cloud Armor 中基于路径的 IP 限制策略

- error 
```bash
ERROR: (gcloud.compute.security-policies.rules.create) Could not fetch resource:
 - Invalid value for field 'resource.match.expr.expression': '[您的表达式]'. The expression has too many subexpressions (maximum 5).ßßß

```

1. 引言：应对 Cloud Armor 中基于路径规则的 IP 列表限制
   在 Google Cloud Armor 安全策略中，针对特定 URL 路径（Location Path）配置基于 IP 地址的访问限制是一项常见的安全需求。然而，当需要纳入的 IP 地址或 CIDR 地址段数量（例如，用户提及的六个或更多）接近或超过单条规则所能承载的上限时，便会遇到配置上的挑战。用户观察到，将路径条件与 IP 白名单结合可能触及规则的复杂度限制，这是实际操作中确实存在的情况。
   随着应用程序的扩展和安全需求的演进，受信或受限的 IP 列表往往会不断增长。因此，采用一种可扩展的 IP 管理方法对于维持有效的安全态势至关重要，同时避免产生过度的管理开销或触及平台的技术限制。Cloud Armor 提供了强大的 L3 至 L7 层过滤能力 ，但深刻理解其工作机制和限制是实现高效防护的前提。任何复杂的分布式系统，为了保证整体性能、稳定性以及资源公平使用，都会设定相应的配额和限制 。这种设计并非 Cloud Armor 所独有，它反映了在提供精细化控制能力与维持系统高效运作之间的固有平衡。
   本报告旨在分析在 Cloud Armor 中管理特定路径下 IP 列表限制的约束条件，评估包括用户提出的多规则优先级方案在内的潜在解决方案，并针对此场景推荐最具扩展性和管理性的最佳实践。其核心目标是为云工程师和安全管理员提供清晰、可操作的指导，以应对 IP 列表规模增长带来的挑战，确保安全策略的长期有效性和可维护性。
2. 理解 Cloud Armor 规则中 IP 匹配的限制条件
   Google Cloud Armor 规则在匹配传入流量时，对于 IP 地址和表达式的复杂性设定了明确的限制。这些限制直接影响着如何为特定路径配置包含多个 IP 地址或范围的白名单或黑名单。

- 单条规则中 IP 地址/范围的限制
  当使用基本匹配条件（通过 Google Cloud CLI 中的 --src-ip-ranges 标志定义）或在高级规则的自定义表达式中单独列出 IP 地址时，单条规则能够包含的 IP 地址或 IP 地址范围（CIDR）的最大数量为 10 个 。此限制同时适用于 IPv4 和 IPv6 地址范围。这意味着，如果需要为一个特定路径允许超过 10 个独立的 IP 地址或 CIDR 段，直接在单条规则中列出所有这些 IP 将会超出此硬性限制，从而导致配置失败。
- 高级规则中逻辑子表达式和字符数的限制
  Cloud Armor 的高级规则使用通用表达式语言 (Common Expression Language, CEL) ，允许用户构建更复杂的匹配逻辑。然而，这类规则同样受到限制：
  - 子表达式数量：一条高级规则最多可以组合 5 个子表达式 。在基于路径的 IP 限制场景中，一个路径匹配条件（如 request.path.startsWith('/admin')）本身可视为一个子表达式，而每一个 inIpRange(origin.ip, '1.2.3.4/32') 这样的 IP 地址检查也可能被计为一个子表达式的部分。如果用户希望通过逻辑或 (||) 连接多个 IP 地址检查，并与路径条件通过逻辑与 (&&) 结合，子表达式的数量很容易达到上限。
  - 字符数限制：每个子表达式的字符数上限为 1024 个字符，而整个自定义表达式的总字符数上限为 2048 个字符 。虽然对于仅包含约六个 IP 地址的场景，字符数限制可能不是首要瓶颈，但在构建包含多个 IP 和其他条件的复杂规则时，也需要关注此限制。
- 对用户场景的影响
  如果用户需要为特定路径（例如 /specific/path）允许六个不同的 IP CIDR，并且每个 IP 检查与路径条件结合，即便 IP 数量未超过 10 个的直接限制，也可能因规则的整体复杂度（如子表达式数量）而变得难以管理或接近限制。若尝试直接列出超过 10 个 IP/CIDR，则会明确违反规定。这些限制的存在，是为了确保 Cloud Armor 在 Google 全球边缘网络 进行规则评估时能够保持高性能和低延迟。边缘节点需要快速处理海量请求，过于复杂的单条规则会消耗更多计算资源，可能导致延迟增加，影响用户体验和系统整体效率。因此，这些配额和限制是维持系统稳定性、资源公平使用和可预测性能的必要措施 。
  下表总结了与基于 IP 和路径的规则相关的关键 Cloud Armor 配额与限制：
  表 1：Cloud Armor 关键配额与限制
  | 资源/项目 | 限制 | 参考资料 |
  | ---------------------------------------------------------------------- | ------------ | -------- |
  | 每条规则的 IP 地址或 IP 地址范围数量 (基本条件或单独的 inIpRange 调用) | 10 | |
  | 每条包含自定义表达式的规则的子表达式数量 | 5 | |
  | 自定义表达式中每个子表达式的字符数 | 1024 | |
  | 自定义表达式的总字符数 | 2048 | |
  | 地址组容量 (IPv4 范围示例) | 高达 150,000 | |
  | 地址组容量 (IPv6 范围示例) | 高达 50,000 | |
  理解这些限制是设计有效且可扩展的 Cloud Armor 安全策略的基础。试图通过在单条规则中强行塞入过多 IP 地址并非长久之计，这促使我们需要寻找更为结构化和可扩展的管理方法。

3. 方法一：利用具有不同优先级的多条规则（用户考量）
   用户提出的一种潜在解决方案是为同一个 Location Path 创建多条具有不同优先级的规则，每条规则包含一部分允许访问的 IP 地址段。

- 方法说明
  此方法涉及创建多条安全规则，它们都针对相同的请求路径，例如 request.path == '/your/location/path'。每条规则将包含一部分 IP 地址或 CIDR 范围（每条规则最多 10 个）。
  例如，若要允许 IP 段 1.1.1.0/24、2.2.2.0/24、3.3.3.0/24、4.4.4.0/24、5.5.5.0/24 和 6.6.6.0/24 访问路径 /foo，可以配置如下：
  - 规则 1 (优先级 100): request.path == '/foo' && (inIpRange(origin.ip, '1.1.1.0/24') | | inIpRange(origin.ip, '2.2.2.0/24'))，操作: allow
  - 规则 2 (优先级 101): request.path == '/foo' && (inIpRange(origin.ip, '3.3.3.0/24') | | inIpRange(origin.ip, '4.4.4.0/24'))，操作: allow
  - 规则 3 (优先级 102): request.path == '/foo' && (inIpRange(origin.ip, '5.5.5.0/24') | | inIpRange(origin.ip, '6.6.6.0/24'))，操作: allow
  - 可能还需要一条优先级更低（数值更大）的规则（例如，优先级 1000）来拒绝其他访问该路径的 IP：request.path == '/foo'，操作: deny(403)。
- 规则优先级评估
  Cloud Armor 依照规则的优先级数值从小到大（即逻辑优先级从高到低）的顺序评估规则 。当一个请求匹配到某条规则时，该规则定义的操作将被执行，并且具有更高优先级数值（逻辑优先级更低）的后续规则将不再针对此请求进行评估 。这证实了用户的直觉，即通过为相同路径设置不同优先级的规则，可以实现累积允许特定 IP 列表的效果。
- 优点
  - 概念简单（适用于少量 IP）: 对于仅略微超过单规则 IP 限制（例如 12-15 个 IP，需要 2 条规则）的场景，此方法在初期易于理解和实施。
  - 可能无需企业版（若无其他高级表达式需求）: 如果规则保持基本（仅 IP 范围和路径），理论上此方法不强制要求 Cloud Armor 企业版。然而，路径和 IP 的组合通常意味着使用高级表达式。
- 缺点
  - 可扩展性问题: 随着 IP 地址范围数量的增长，规则数量会激增。管理 6 个 IP 段可能只需要 1-3 条规则，但若 IP 列表增长到 60 个，则可能需要 6 条或更多规则，这将变得非常 cumbersome。
  - 规则配额消耗: 每条规则都会计入每个安全策略和每个项目允许的总规则数配额 。如果许多路径都需要类似的处理，这种方法会迅速消耗可用的规则配额。例如，“每个项目的全局安全策略规则数”是有限的 。
  - 管理复杂性:
    - 更新 IP 列表时，需要识别并修改多条规则中的某一条或几条。
    - 确保多条规则中路径定义和操作的一致性，增加了人为错误的风险。
    - 审计和理解特定路径的整体策略逻辑变得更加困难，因为需要汇总来自多条规则的信息。
  - 潜在的优先级冲突: 如果管理不当，引入新规则或调整现有规则的优先级可能导致意外行为，如 中所述的“测试您的逻辑”部分强调的那样。
- 何时可作为临时或有限的解决方案
  此方法可能适用于 IP 地址数量非常少（例如，略多于 10 个，仅需 2 条规则）且 IP 列表相对静态或极少变更的情况。然而，这种方法本质上是一种战术性规避，它用长期的运营健康和可扩展性换取了在处理少量溢出 IP 时短期的实施便利性。它并未从根本上解决大规模 IP 列表管理的问题。单规则 IP 数量限制（原因）导致用户考虑多规则方案（效果）。虽然这在功能上对少量 IP 有效，但随着 IP 数量的增长，会对规则配额使用和可管理性产生负面影响（次级效应）。这揭示了一种常见的系统配置反模式：用一个本身扩展性不佳的方案去解决一个扩展性问题。

4. 方法二（推荐）：利用地址组实现可扩展的 IP 管理
   针对在 Cloud Armor 规则中管理大量 IP 地址的挑战，Google Cloud 提供了“地址组”（Address Groups，曾称为“命名 IP 地址列表”）功能，这是一种更为高效和可扩展的解决方案。

- 地址组简介
  地址组是集中管理 IP 地址或 CIDR 范围的集合 。它们的主要目的是通过允许在多个安全策略或规则中复用这些 IP 列表，来简化配置和维护工作 。这代表了一种从将 IP 列表直接嵌入规则逻辑到将其抽象为可管理的独立实体的转变，遵循了良好的软件和配置设计原则——关注点分离。
- 地址组如何克服单规则 IP 限制
  核心优势在于，一个地址组可以容纳远超单条规则限制的大量 IP 地址或范围。例如，一个地址组最多可包含 150,000 个 IPv4 地址范围或 50,000 个 IPv6 地址范围 。安全策略中的单条规则随后可以引用这个地址组，从而有效地将规则条件应用于组内所有 IP，而无需在规则表达式中单独列出它们。
- 主要优势
  - 可扩展性: 能够轻松管理包含数十、数百甚至数千个 IP 地址的列表。
  - 集中管理: 在一个地方（地址组）更新 IP 列表，所有引用该地址组的规则都会自动更新 。这极大地减少了出错的可能性和管理工作量。
  - 可复用性: 同一个地址组（例如，“trusted_partner_ips”）可以在不同安全策略的多条规则中按需使用。
  - 清晰度和可读性: 规则表达式变得更加简洁明了，例如使用 evaluateAddressGroup('allowed-ips-for-path-X', origin.ip) 而不是一长串 inIpRange() 调用。
- 前提条件
  - Google Cloud Armor 企业版: 强调在安全策略中使用地址组功能，要求项目必须已订阅 Cloud Armor 企业版服务 。这是用户需要考虑的一个关键因素。Cloud Armor 企业版对地址组的要求表明，Google 将这种级别的 IP 管理可扩展性视为一项高级功能，通常为具有更复杂安全需求的大型组织所需要，这与典型的企业软件分层定价策略相符，对用户而言具有成本考量。
  - 必须启用网络安全 API (networksecurity.googleapis.com) 。
- 创建和填充地址组的概要步骤 (详细步骤参考 )
  可以通过 Google Cloud 控制台或 gcloud 命令行工具进行操作。
  - 指定名称、范围（对于 Cloud Armor 后端安全策略，通常为全局）、类型 (IPv4/IPv6)、用途（CLOUD_ARMOR 或 DEFAULT,CLOUD_ARMOR）和容量。
  - 向地址组中添加 IP 地址或 CIDR 范围。
    单规则 IP 数量的限制（原因）以及管理更大型列表的需求（原因）共同推动了地址组这一功能（效果/解决方案）的产生。地址组的存在，反过来又使得构建更具可扩展性和可维护性的安全策略成为可能（次级效应）。

5. 通过地址组实现特定路径的 IP 限制
   结合地址组和 Cloud Armor 的高级规则表达式，可以有效地为特定 URL 路径配置可扩展的 IP 访问限制。

- 构建高级规则表达式 (CEL)
  Cloud Armor 的高级规则采用通用表达式语言 (CEL) ，它提供了强大的灵活性来定义复杂的匹配条件。对于本场景，表达式需要结合路径匹配和地址组评估。
- 结合 request.path 条件与 evaluateAddressGroup()
  - 路径匹配:
    - request.path.startsWith('/your/location/path')：用于前缀匹配，例如允许访问 /your/location/path 及其所有子路径 。
    - request.path == '/your/exact/location/path'：用于精确匹配特定路径。
    - request.path.matches('your_regex_pattern')：用于更复杂的基于正则表达式的路径匹配 。
  - 地址组评估:
    - evaluateAddressGroup('your-address-group-name', origin.ip)：此函数判断请求的源 IP (origin.ip) 是否存在于名为 your-address-group-name 的地址组中。如果存在，则返回 true 。
  - 使用逻辑与 (&&) 结合:
    核心解决方案是将路径条件和地址组评估通过逻辑 && (AND) 操作符连接起来，确保两个条件同时满足时规则才匹配。例如：request.path.startsWith('/your/location/path') && evaluateAddressGroup('your-address-group-name', origin.ip) 。
- 示例规则结构 (概念性)

  - 策略名称: my-app-security-policy
  - 规则优先级: 例如 100 (根据策略结构选择，参考 关于优先级间隔的建议)
  - 描述: "允许来自预批准合作伙伴 IP 的流量访问 /sensitive-data 路径" (参考 关于规则描述的建议)
  - 匹配条件 (高级模式):
    request.path.startsWith('/sensitive-data') && evaluateAddressGroup('partner-ips-for-sensitive-data', origin.ip)

  - 操作: allow
  - 地址组 partner-ips-for-sensitive-data: 包含用户需要管理的 6 个（或更多）IP 地址范围。

- 处理“拒绝其他”情况
  为确保只有地址组中的 IP 能够访问指定路径，通常需要配置一条优先级较低（数值更大）的规则来拒绝其他访问该路径的流量，或者依赖于安全策略的默认拒绝规则。
  - 示例拒绝规则 (如果不依赖默认拒绝):
    _ 优先级: 200 (逻辑优先级低于上述允许规则)
    _ 匹配条件: request.path.startsWith('/sensitive-data') \* 操作: deny(403)
    CEL 在 L7 属性匹配（如 request.path）方面的灵活性与地址组在 L3 IP 管理方面的可扩展性相结合，创造了一种强大的协同效应。这使得用户能够制定出既高度具体又具备良好扩展性的安全策略，而无需在精细的路径控制和可扩展的 IP 管理之间做出取舍。
    下表对比了针对特定路径规则的两种 IP 管理策略：
    表 2：针对特定路径规则的 IP 管理策略对比

| 特性/考量因素                | 多条独立规则方法                                                               | 地址组方法                                           |
| ---------------------------- | ------------------------------------------------------------------------------ | ---------------------------------------------------- |
| 每个逻辑单元处理的最大 IP 数 | 受限于每条规则 10 个 IP，需要增加规则数量                                      | 非常高 (例如，每个组 15 万个 IPv4)，作为一个单元管理 |
| IP 列表增长的可扩展性        | 差；需要添加更多规则                                                           | 优秀；向组中添加 IP，规则保持不变                    |
| 可管理性与维护               | 高；需修改多条规则，存在不一致风险                                             | 低；更新一个中央地址组                               |
| 规则配额影响                 | 高；每个 IP 子集消耗一条规则                                                   | 低；通常每个路径一条规则，无论组内 IP 数量如何       |
| 策略逻辑清晰度               | 规则过多时可能变得模糊                                                         | 更清晰；规则意图更明显                               |
| Cloud Armor 服务层级要求     | 基本规则可能标准版即可（但路径+IP 通常意味着高级规则）。高级规则用于路径匹配。 | 使用地址组于策略中需要 Cloud Armor 企业版            |
| IP 列表的可复用性            | 低；IP 嵌入在特定规则中                                                        | 高；地址组可被多条规则/策略引用                      |

此表格清晰地展示了在处理用户所述的（例如六个或更多 IP）及未来可能增长的 IP 列表时，地址组方法在可扩展性、可管理性和资源利用效率方面的显著优势。 6. 配置与维护的最佳实践
在配置 Cloud Armor 安全策略，特别是涉及 IP 限制和路径匹配的规则时，遵循最佳实践对于确保策略的有效性、可维护性和避免意外中断至关重要。这些实践不仅仅是建议，更是降低复杂网络安全策略管理相关运营风险的关键。

- 战略性规则优先级分配
  - 规则优先级数值越小，逻辑优先级越高。规则按此顺序进行评估。
  - 预留间隔: 在初次配置规则时，在各规则的优先级数值之间预留一定的间隔（例如，间隔 10 或 100）。这样做便于将来在不重新调整所有规则优先级的情况下插入新规则。
  - 分组相似规则: 将功能或目标相似的规则通过优先级段进行分组，并在不同组之间设置更大的间隔 。例如，所有与 /admin 路径访问相关的规则可以位于 100-199 优先级范围，而 /api 相关的规则则位于 200-299 范围。
- 使用预览模式进行彻底测试
  - 在强制执行任何新的或修改过的规则（特别是复杂的或包含拒绝操作的规则）之前，务必使用 Cloud Armor 的“预览模式”。
  - 预览模式允许观察规则对实时流量将会采取何种操作，而不会实际阻止或允许流量 。
  - 这对于验证规则逻辑、避免对生产流量产生意外负面影响至关重要。
- 维护清晰的规则描述
  - 利用每条规则的描述字段（最多 64 个字符）提供上下文信息：创建原因、预期功能、相关的工单号或指向外部文档的引用 。
  - 这对于未来的审计、故障排除和团队协作非常有价值。
- 定期审查和更新地址组
  - IP 列表通常是动态变化的（例如，新的合作伙伴 IP、旧系统停用的 IP）。
  - 应建立定期审查和更新地址组内容的流程，以确保其保持准确和相关。
  - 过时的 IP 列表可能导致安全漏洞（如果恶意 IP 未被添加到拒绝列表）或访问问题（如果合法的新 IP 未被添加到允许列表）。
- 全面测试逻辑
  - 除了预览模式，还应主动测试规则之间的交互，特别是针对相同资源的允许/拒绝逻辑。 提供了一个示例，说明了高优先级的允许规则如何覆盖低优先级的拒绝规则，如果不仔细规划，这可能与直觉相悖。
  - 对于用户的场景：确保“允许来自地址组 X 的 IP 访问路径 Y”的规则具有比通用的“拒绝所有访问路径 Y”的规则更高的逻辑优先级（即更小的优先级数值）。
- 考虑为 POST 请求体启用 JSON 解析
  - 如果特定路径涉及包含 JSON 主体的 POST 请求，并且同时使用了预配置的 WAF 规则，请确保启用 JSON 解析。否则，Cloud Armor 不会解析 POST 主体中的 JSON 内容以供预配置 WAF 规则检查，可能导致 WAF 签名的误报或漏报。虽然这不直接关系到 IP 列表，但在涉及路径特定逻辑的策略中是一项通用的最佳实践。
    未能遵循这些最佳实践可能导致配置错误、安全漏洞或服务中断。例如，不预留优先级间隔 可能意味着一个简单的规则添加就需要重新编号数十个现有规则，从而增加了每次更改的出错风险。良好的实践能够带来更具弹性和可靠性的安全性，而不良实践则会导致配置脆弱，难以更改且容易出错，久而久之可能会削弱 Cloud Armor 的防护效果。

7. 结论与战略建议
   针对在 Google Cloud Armor 中为特定 Location Path 管理六个或更多 IP 地址/范围的限制问题，本报告进行了深入分析。

- 地址组是最佳解决方案的重申
  对于用户面临的挑战，即需要为一个特定路径管理数量可观（如用户提及的六个或更多）且可能增长的 IP 地址列表，地址组 (Address Groups) 无疑是 Google Cloud Armor 中推荐的、最具可扩展性的解决方案。
- 地址组方案优势总结
  与创建多条具有不同优先级的独立规则相比，地址组方案在以下方面表现出显著优势：
  - 可扩展性: 能够轻松应对大规模 IP 列表的管理需求。
  - 集中管理: IP 列表的更新集中在地址组层面，自动应用到所有引用规则，极大简化维护。
  - 规则清晰度: 保持安全策略规则的简洁和易读性。
  - 规则配额效率: 更有效地利用有限的规则配额。
    （参考上文表 2 的详细对比）
- Cloud Armor 企业版前提条件的确认
  需要再次强调，在安全策略中有效利用地址组功能，要求用户的 Google Cloud 项目已订阅 Cloud Armor 企业版 (Cloud Armor Enterprise tier) 。如果项目当前未使用企业版，则需要评估升级的成本效益。若不升级，则只能接受多规则方法的局限性，该方法仅适用于管理少量且静态的 IP 集合。
- 规划与实施的最终建议
  - 前瞻性规划: 从一开始就以可扩展性为目标来设计安全策略。预见到 IP 列表可能增长的情况，并优先考虑使用地址组。
  - 谨慎迁移: 如果当前已采用多规则方法，并计划迁移到地址组，应仔细规划过渡过程，并充分利用预览模式进行验证，确保平稳切换。
  - 持续维护: 建立定期审查和更新地址组内容以及相关安全策略规则的机制，确保其长期有效性和准确性。
    选择战术性规避方案（多规则）还是战略性解决方案（地址组），往往需要在即时投入/成本与长期运营效率和可扩展性之间进行权衡。“企业版”是此决策中的一个关键因素。然而，考虑到单规则的 IP 数量限制 与地址组的巨大容量 之间的显著差异，对于任何具有一定规模或增长预期的 IP 管理需求，地址组在技术上的优越性是显而易见的。用户应基于其具体情况（当前 IP 列表规模、预期增长、企业版预算、运营效率的重要性）做出明智决策。
