Flux CD Flux CD

使用 Flux 设置多租户

为每个团队提供各自的命名空间和仓库,并通过 Kubernetes RBAC 强制隔离。

15 min 高级

当多个团队共享一个集群时,你希望每个团队都能部署自己的应用,而无法触碰他人的应用。Flux 在 Kubernetes 原语之上构建了这一点:每个租户获得一个命名空间、一个 service account 和一个 role binding,Flux 在模拟该 service account 的身份下应用租户的清单。隔离由 Kubernetes RBAC 强制执行,不需要单独的策略引擎。本指南设置一个名为 dev-team 的租户。

两种角色

  • 平台管理员拥有集群和 Flux 安装。他们创建租户,并决定每个租户可以访问什么。
  • 租户拥有他们自己的应用。他们把清单提交到自己的仓库,Flux 仅在租户的命名空间内应用它们。

创建租户

CLI 会为你生成命名空间、service account 和 RBAC。在平台仓库的克隆中运行:

mkdir -p tenants/base/dev-team
flux create tenant dev-team \
  --with-namespace=apps \
  --export > tenants/base/dev-team/rbac.yaml

生成的 YAML 包含一个名为 apps 的 Namespace、一个名为 dev-team 的 ServiceAccount,以及一个 RoleBinding,它授予该 service account 仅在 apps 命名空间内的 cluster-admin 角色。它无法在该命名空间之外做任何事情。

连接租户的仓库

在租户的命名空间中,为租户自己的仓库创建一个 source 和 Kustomization:

flux create source git dev-team \
  --namespace=apps \
  --url=https://github.com/your-org/dev-team-apps \
  --branch=main \
  --export > tenants/base/dev-team/sync.yaml

flux create kustomization dev-team \
  --namespace=apps \
  --service-account=dev-team \
  --source=GitRepository/dev-team \
  --path="./" \
  --prune=true --interval=5m \
  --export >> tenants/base/dev-team/sync.yaml

重要的一行是 Kustomization 上的 serviceAccountName: dev-team。它让 kustomize-controller 以该 service account 的身份应用租户的清单,因此任何试图在 apps 之外创建资源、或创建 ClusterRole 之类集群范围资源的尝试,都会被 Kubernetes API 拒绝。HelmRelease 上也有同样的字段。

在 tenants/base/dev-team/ 中添加一个列出 rbac.yaml 和 sync.yaml 的 kustomization.yaml,并从集群的文件夹中引用该租户,例如通过 clusters/production/tenants.yaml 中 path: ./tenants/production 的 Flux Kustomization。提交并推送。Flux 会创建命名空间、RBAC 和租户的同步,随后由团队自己的仓库接管。

对于私有的租户仓库,请在租户的命名空间中创建凭据,这样只有该租户的对象会引用它们:

flux create secret git dev-team-auth \
  --namespace=apps \
  --url=https://github.com/your-org/dev-team-apps \
  --username=git --password=<token>

然后在 source 中添加 --secret-ref=dev-team-auth。

锁定控制器

只有当租户无法绕过 service account 时,它们才有意义。请通过修补 clusters/<env>/flux-system/kustomization.yaml 中的 Flux 安装,配置控制器来强制执行这些规则:

patches:
  - patch: |
      - op: add
        path: /spec/template/spec/containers/0/args/-
        value: --no-cross-namespace-refs=true
      - op: add
        path: /spec/template/spec/containers/0/args/-
        value: --default-service-account=default
    target:
      kind: Deployment
      name: "(kustomize-controller|helm-controller)"
  - patch: |
      - op: add
        path: /spec/template/spec/containers/0/args/-
        value: --no-cross-namespace-refs=true
    target:
      kind: Deployment
      name: "(notification-controller|image-reflector-controller|image-automation-controller)"

这些参数的作用:

  • --no-cross-namespace-refs=true 阻止租户的 Kustomization 引用另一个命名空间中的 source,所以租户无法使用彼此的仓库或凭据。
  • --default-service-account=default 使控制器在对象没有设置 service account 时,模拟该对象所在命名空间中的 default service account。忘记设置 serviceAccountName 的租户只会得到几乎没有任何权限的身份,而不是 Flux 的 cluster-admin 身份。

将这些补丁提交到 bootstrap 在该文件夹中生成的 kustomization.yaml 里。重新运行 bootstrap 会保留你添加到该文件中的自定义内容。请查看当前的 Flux 多租户文档,了解适用于你版本的确切补丁。

限制租户能做什么

在命名空间边界之外,考虑额外的控制:

  • 命名空间范围的 RBAC。 如果租户不应当创建例如 Role 或 NetworkPolicy,请用更窄的角色替换生成的 cluster-admin 角色绑定。
  • 准入策略。 使用 Kyverno 或 ValidatingAdmissionPolicy 来强制镜像仓库、资源限制,或禁止特权 Pod。
  • 配额。 在 RBAC 之外,为租户命名空间添加 ResourceQuota 和 LimitRange。
  • 网络隔离。 添加默认拒绝的 NetworkPolicy 对象,使租户命名空间之间无法互相通信。

验证隔离

向租户的仓库添加一个会在租户命名空间之外创建东西的清单,比如一个 ClusterRole,然后推送。接着检查:

flux get kustomizations -n apps
kubectl describe kustomization dev-team -n apps

Kustomization 会以一个指明 service account 的 forbidden 错误失败,这正是你想要的。移除有问题的清单后,Flux 会自行恢复。

与基于项目的租户模型的比较

有些工具将租户建模为带有各自策略对象的项目。Flux 没有这样的概念。租户只是一个命名空间加上一个 Flux 所模拟的 service account,这意味着 Kubernetes API 服务器是唯一强制执行权限的地方。

热门指南