Flux CD Flux CD

Mandantenfähigkeit mit Flux einrichten

Gib jedem Team einen eigenen Namespace und ein eigenes Repository und setze die Isolation mit Kubernetes RBAC durch.

15 min Experte

Wenn sich mehrere Teams einen Cluster teilen, soll jedes seine eigenen Anwendungen deployen können, ohne die der anderen anzufassen. Flux baut das auf Kubernetes-Primitiven auf: Jeder Mandant bekommt einen Namespace, einen Service Account und ein Role Binding, und Flux wendet die Manifeste des Mandanten an, während es diesen Service Account impersoniert. Die Isolation wird durch Kubernetes RBAC durchgesetzt, eine separate Policy-Engine ist nicht nötig. Diese Anleitung richtet einen Mandanten namens dev-team ein.

Die zwei Rollen

  • Plattform-Admins besitzen den Cluster und die Flux-Installation. Sie erstellen Mandanten und entscheiden, worauf jeder zugreifen darf.
  • Mandanten besitzen ihre Anwendungen. Sie committen Manifeste in ihr eigenes Repository, und Flux wendet sie nur im Namespace des Mandanten an.

Den Mandanten erstellen

Die CLI erzeugt Namespace, Service Account und RBAC für dich. Führe sie in einem Clone des Plattform-Repositorys aus:

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

Das erzeugte YAML enthält einen Namespace namens apps, einen ServiceAccount namens dev-team und ein RoleBinding, das diesem Service Account die Rolle cluster-admin nur innerhalb des Namespaces apps gewährt. Außerhalb davon kann er nichts tun.

Das Repository des Mandanten anbinden

Erstelle eine Source und eine Kustomization für das eigene Repository des Mandanten, im Namespace des Mandanten:

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

Die wichtige Zeile ist serviceAccountName: dev-team an der Kustomization. Sie bringt den kustomize-controller dazu, die Manifeste des Mandanten als dieser Service Account anzuwenden, sodass jeder Versuch, Ressourcen außerhalb von apps oder clusterweite Ressourcen wie eine ClusterRole zu erstellen, von der Kubernetes-API abgelehnt wird. Dasselbe Feld gibt es bei HelmRelease.

Füge in tenants/base/dev-team/ eine kustomization.yaml hinzu, die rbac.yaml und sync.yaml auflistet, und referenziere den Mandanten aus dem Ordner des Clusters, zum Beispiel über eine Flux-Kustomization in clusters/production/tenants.yaml mit path: ./tenants/production. Committe und pushe. Flux erstellt den Namespace, das RBAC und die Synchronisierung des Mandanten, und das eigene Repository des Teams übernimmt von dort.

Für ein privates Mandanten-Repository erstelle die Zugangsdaten im Namespace des Mandanten, sodass nur Objekte dieses Mandanten darauf verweisen:

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

Füge dann der Source --secret-ref=dev-team-auth hinzu.

Die Controller absichern

Service Accounts helfen nur, wenn Mandanten sie nicht umgehen können. Konfiguriere die Controller so, dass sie die Regeln durchsetzen, indem du die Flux-Installation in clusters/<env>/flux-system/kustomization.yaml patchst:

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)"

Was diese Flags bewirken:

  • --no-cross-namespace-refs=true verhindert, dass die Kustomization eines Mandanten eine Source in einem anderen Namespace referenziert, sodass Mandanten weder die Repositories noch die Zugangsdaten der anderen nutzen können.
  • --default-service-account=default lässt Controller den Service Account default im Namespace des Objekts impersonieren, wenn keiner gesetzt ist. Ein Mandant, der serviceAccountName vergisst, bekommt fast keine Berechtigungen statt Fluxs Cluster-Admin-Identität.

Committe die Patches in die von Bootstrap erzeugte kustomization.yaml in diesem Ordner. Erneutes Ausführen von Bootstrap behält Anpassungen, die du in dieser Datei hinzufügst. Prüfe die aktuelle Flux-Dokumentation zur Mandantenfähigkeit auf den exakten Patch für deine Version.

Einschränken, was Mandanten tun können

Über die Namespace-Grenze hinaus kommen zusätzliche Kontrollen in Betracht:

  • Namespace-bezogenes RBAC. Ersetze das erzeugte cluster-admin-Role-Binding durch eine engere Rolle, wenn Mandanten etwa keine Roles oder NetworkPolicies erstellen sollen.
  • Admission Policy. Nutze Kyverno oder eine ValidatingAdmissionPolicy, um Image-Registries, Ressourcenlimits durchzusetzen oder privilegierte Pods zu verbieten.
  • Quotas. Füge dem Mandanten-Namespace neben dem RBAC eine ResourceQuota und eine LimitRange hinzu.
  • Netzwerkisolation. Füge Default-Deny-NetworkPolicy-Objekte hinzu, damit Mandanten-Namespaces nicht miteinander sprechen können.

Die Isolation prüfen

Füge dem Repository des Mandanten ein Manifest hinzu, das etwas außerhalb des Mandanten-Namespaces erstellt, etwa eine ClusterRole, und pushe. Prüfe dann:

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

Die Kustomization schlägt mit einem Forbidden-Fehler fehl, der den Service Account nennt, und genau das willst du. Entferne das fehlerhafte Manifest, und Flux erholt sich von selbst.

Vergleich mit projektbasierter Mandantenfähigkeit

Manche Werkzeuge modellieren Mandanten als Projekte mit eigenen Policy-Objekten. Flux kennt kein solches Konzept. Ein Mandant ist schlicht ein Namespace plus ein Service Account, den Flux impersoniert, was bedeutet, dass der Kubernetes-API-Server der einzige Ort ist, an dem Berechtigungen durchgesetzt werden.

Beliebte Anleitungen