LabHub
学习 学习路径 课程

Istio 服务网格

从全面拒绝一路收窄到最小权限

在 LabHub 中继续学习

目标

从默认拒绝出发,仅按调用图开放权限,从而构建最小权限授权,并能够用矩阵说明每次调用的结果。

为什么重要

授权设计中最常见的错误,是采用逐一阻止不需要内容的方向。这样一来,遗漏的路径会永远保持开放,而且无人知晓。相反,从全面拒绝出发,遗漏的路径会立即以 403 暴露出来,因此设计能够闭环。Istio 用一行 spec: {} 表达这种反转——ALLOW 策略存在,却没有任何匹配规则,所以任何请求都无法通过。

还必须熟练掌握评估顺序。顺序是 CUSTOM → DENY → ALLOW,而 ALLOW 的规则是“只要存在任意一个策略,请求就必须匹配才能通过”。也就是说,**首次添加 ALLOW 策略的瞬间,该工作负载便会切换为白名单模式。**不了解这一点而添加一条策略,导致现有流量全部被阻断,是常见事故。DENY 先于 ALLOW 评估这一特性,反过来可以成为安全网——对于管理路径这类“无论如何都必须阻止”的内容,再额外铺设一层 DENY。

最后,授权策略的 principals 来自 mTLS 证书中的身份。以明文进入的请求没有 principal,因此绝不可能匹配,所以 切换到 STRICT 是授权的前提条件

步骤

**开始前的准备。**每次实验都会启动新的实验 Pod,因此不会保留前一实验的服务网格设置。如果 kubectl get crd authorizationpolicies.security.istio.io 没有输出,请执行 istioctl manifest generate --set profile=minimal > /root/istio/manifest.yaml,然后将 kubectl apply -f /root/istio/manifest.yaml 执行两次,再通过 kubectl create ns mesh-lab && kubectl label ns mesh-lab istio-injection=enabled 准备命名空间。第 2 步和第 4 步中 selector 指向的 payments、ratings 工作负载也需要在本实验中重新创建。

  1. mesh-lab 中创建 AuthorizationPolicy deny-all——只保留 spec: {},在没有 selector 和 rules的情况下应用(省略 action,使用默认值 ALLOW)。并在 /root/istio/authz/out/denyall-note.txt 中写明没有规则时任何请求都无法通过的原因。
  2. mesh-lab 中创建 ServiceAccount frontend(如果不存在前一实验的 payments 工作负载,也请一并创建),再创建 AuthorizationPolicy allow-frontendselector.matchLabels.apppaymentsactionALLOW,并在 rules[0].from[0].source.principals 中填写 cluster.local/ns/mesh-lab/sa/frontend不得添加 spiffe:// 前缀。
  3. 在同一个 allow-frontend 策略中添加 rules[0].to[0].operationmethods 只能有 ["GET"] 一项paths 中应包含 /api/*。并在 /root/istio/authz/out/path-note.txt 中写明路径匹配不是正则表达式,只支持前缀/后缀通配符。
  4. mesh-lab 中创建 ratings 工作负载(Service ratings、Deployment ratings-v1、Pod 标签 app: ratings),再创建 AuthorizationPolicy allow-mesh-labselector.matchLabels.appratingsrules[0].from[0].source.namespaces["mesh-lab"]。并在 /root/istio/authz/out/ns-note.txt 中写明,命名空间级控制比服务账号(principal)级控制更粗粒度。
  5. mesh-lab 中创建 AuthorizationPolicy deny-adminactionDENY,并在 rules[0].to[0].operation.paths 中包含 /admin/*。然后在 /root/istio/authz/order.txt 中将评估顺序每行写一个,共三行——第一行写 CUSTOM,第二行写 DENY,第三行写 ALLOW(不得全部写在同一行)。
  6. mesh-lab 中创建 AuthorizationPolicy allow-v2-clients。在 rules[0].when 中设置两个条件:一个是 key: request.headers[x-api-version],值为 values: ["v2"];另一个是 key: source.namespace,值为 notValues: ["legacy"]使用 notValues 的条件,其 key 中不得包含 request.headers
  7. mesh-lab 中创建 AuthorizationPolicy audit-sensitiveactionAUDIT,在 rules[0].to[0].operation.paths 中指定要审计的路径(例如 /internal/*)。并在 /root/istio/authz/out/audit-note.txt 中同时写明,AUDIT 不会阻止流量,只会记录,以及它可用于在真正启用策略前预先查看影响。
  8. 创建 /root/istio/authz/out/authz-matrix.jsoncases 数组中应包含至少 6 条记录,每项都必须包含 expected(只能是 "allow""deny")和 policy(产生该结果的策略名称——必须真实存在于 mesh-lab 中,且是一个不含空格的单词)。至少需要 2 条预期允许和 2 条预期拒绝的记录。mesh-lab 中必须至少存在 5 个 AuthorizationPolicy;将 istioctl analyze -n mesh-lab 的结果保存到 /root/istio/authz/out/analyze.txt,其中不得出现 Error [

参考

用空规则建立全面拒绝

mesh-lab 中创建 AuthorizationPolicy deny-all——只保留 spec: {},在没有 selector 和 rules的情况下应用(省略 action,使用默认值 ALLOW)。并在 /root/istio/authz/out/denyall-note.txt 中写明没有规则时任何请求都无法通过的原因。

没有任何规则的允许策略就是全面拒绝。原因可以从评估顺序的最后一项找到。该策略必须作用于整个命名空间,因此不要设置 selector。

按调用方身份只开放一条路径

mesh-lab 中创建 ServiceAccount frontend(如果不存在前一实验的 payments 工作负载,也请一并创建),再创建 AuthorizationPolicy allow-frontendselector.matchLabels.apppaymentsactionALLOW,并在 rules[0].from[0].source.principals 中填写 cluster.local/ns/mesh-lab/sa/frontend不得添加 spiffe:// 前缀。

策略附加在接收请求的工作负载上。身份不是 IP,而是服务账号;请注意,该字段中不添加前缀。

进一步限定方法和路径

在同一个 allow-frontend 策略中添加 rules[0].to[0].operationmethods 只能有 ["GET"] 一项paths 中应包含 /api/*。并在 /root/istio/authz/out/path-note.txt 中写明路径匹配不是正则表达式,只支持前缀/后缀通配符。

本步骤只允许读取。请确认路径匹配并非正则表达式,并将这一点写入说明。

按命名空间允许访问

mesh-lab 中创建 ratings 工作负载(Service ratings、Deployment ratings-v1、Pod 标签 app: ratings),再创建 AuthorizationPolicy allow-mesh-labselector.matchLabels.appratingsrules[0].from[0].source.namespaces["mesh-lab"]。并在 /root/istio/authz/out/ns-note.txt 中写明,命名空间级控制比服务账号(principal)级控制更粗粒度。

这是比身份级别更粗粒度的控制。请在说明中写明何时这种粒度足够、何时不足。

建立拒绝安全网并写出评估顺序

mesh-lab 中创建 AuthorizationPolicy deny-adminactionDENY,并在 rules[0].to[0].operation.paths 中包含 /admin/*。然后在 /root/istio/authz/order.txt 中将评估顺序每行写一个,共三行——第一行写 CUSTOM,第二行写 DENY,第三行写 ALLOW(不得全部写在同一行)。

拒绝先于允许评估,因此可以防御允许策略中的错误。整理顺序时必须每行写一项。

用条件进行更精细的限制

mesh-lab 中创建 AuthorizationPolicy allow-v2-clients。在 rules[0].when 中设置两个条件:一个是 key: request.headers[x-api-version],值为 values: ["v2"];另一个是 key: source.namespace,值为 notValues: ["legacy"]使用 notValues 的条件,其 key 中不得包含 request.headers

可以设置多个条件,也可以表达排除条件。请将请求头条件和排除条件拆成两个不同的条目。

创建只记录而不阻断的策略

mesh-lab 中创建 AuthorizationPolicy audit-sensitiveactionAUDIT,在 rules[0].to[0].operation.paths 中指定要审计的路径(例如 /internal/*)。并在 /root/istio/authz/out/audit-note.txt 中同时写明,AUDIT 不会阻止流量,只会记录,以及它可用于在真正启用策略前预先查看影响。

这是在真正启用策略前先观察影响的机制。请准确写明它会对流量产生什么影响。

构建逐次调用的允许/拒绝矩阵

创建 /root/istio/authz/out/authz-matrix.jsoncases 数组中应包含至少 6 条记录,每项都必须包含 expected(只能是 "allow""deny")和 policy(产生该结果的策略名称——必须真实存在于 mesh-lab 中,且是一个不含空格的单词)。至少需要 2 条预期允许和 2 条预期拒绝的记录。mesh-lab 中必须至少存在 5 个 AuthorizationPolicy;将 istioctl analyze -n mesh-lab 的结果保存到 /root/istio/authz/out/analyze.txt,其中不得出现 Error [

必须同时写明每次调用为何会由哪条策略作出该决定。策略名称必须真实存在于集群中。