You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
flux2/rfcs/0001-authorization
Stefan Prodan f9e69089ea
Update CLI commands to Notification API v1beta2
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
2 years ago
..
README.md Update CLI commands to Notification API v1beta2 2 years ago

README.md

RFC-0001 Memorandum on Flux Authorization

Summary

This RFC describes in detail, for Flux version 0.24 (Nov 2021), how Flux determines which operations are allowed to proceed, and how this interacts with Kubernetes' access control.

Motivation

To this point, the Flux project has provided examples of how to make a multi-tenant system, but not explained exactly how they relate to Flux's authorization model; nor has the authorization model itself been documented. Further work on support for multi-tenancy, among other things, requires a full account of Flux's authorization model as a baseline.

Goals

  • Give a comprehensive account of Flux's authorization model

Non-Goals

  • Justify the model as it stands; this RFC simply records the state as at v0.24.

Flux's authorization model

The Flux controllers undertake operations as specified by custom resources of the kinds defined in the Flux API. Most of the operations are through the Kubernetes API. Authorization for operations on external systems is not accounted for here.

Flux controllers defer to Kubernetes' native RBAC and namespace isolation to determine which operations are authorized, when processing the custom resources in the Flux API.

In general, Kubernetes API operations are constrained by the service account under which each controller pod runs. In the default deployment of Flux each controller has its own service account; and, the service accounts for the Kustomize controller and Helm controller have the cluster-admin cluster role bound to it.

Both the Kustomize controller and the Helm controller create, update and delete arbitrary sets of configuration that they take as user input. For example, a Kustomization object that references a GitRepository is processed by taking whatever is in the specified Git repository and applying it to the cluster. This is informally called "syncing", and these user-supplied configurations will be called "sync configurations" in the following.

There are five types of access that have a distinct treatment with respect to RBAC and namespace isolation:

  • reading and writing the Flux API object to be processed
  • accessing dependencies of a Flux API object; for example, a secret that holds a decryption key
  • accessing Flux API objects related to the object being processed; for example, a GitRepository referenced by a Kustomization
  • creating, updating and deleting Flux API objects as part of processing; for example, each HelmRelease object contains a template for a Helm chart spec, which the Helm controller uses to create a HelmChart object
  • creating, updating, deleting, and health-checking of arbitrary objects as specified by sync configurations (as mentioned above).

This table summarises how these operations are subject to RBAC and namespace isolation.

Type of operation Accessed via Namespace isolation
Reading and writing the object to be processed Controller service account N/A
Dependencies of object to be processed Controller service account Same namespace only
Access to related Flux API objects Controller service account Some cross-namespace refs[1]
CRUD of Flux API objects Controller service account Created in same namespace
CRUD and healthcheck of sync configurations Impersonation[2] As directed by spec[2]

[1] See "Cross-namespace references" below
[2] See "Impersonation" below

There are two related mechanisms that affect the service account used for the operations marked with "Impersonation" above: "impersonation" and "remote apply". These are explained in the following sections.

Impersonation

The Kustomize controller and Helm controller both apply arbitrary sets of Kubernetes configuration ("synced configuration" as above) to a cluster. These controllers use the service account named in the field .spec.serviceAccountName in the Kustomization and HelmRelease objects respectively, while applying and health-checking the synced configuration. This mechanism is called "impersonation".

The .spec.serviceAccountName field is optional. If empty, the controller's service account is used.

Remote apply

The Kustomize controller and Helm controller are able to apply a set of configuration to a cluster other than the cluster in which they run. If the Kustomization or HelmRelease object refers to a secret containing a "kubeconfig" file, the controller will construct a client using that kubeconfig, and the client is used to apply the prepared set of configuration. The effect of this is that the configuration will be applied as the user given in the kubeconfig; often this is a user with the cluster-admin role bound to it, but not necessarily so.

All accesses that would use impersonation use the remote client instead.

Cross-namespace references

Some Flux API kinds have fields which can refer to a Flux API object in another namespace. The Flux controllers do not respect namespace isolation when dereferencing these fields. The following are fields that are not restricted to the namespace of the containing object, listed by API kind.

API kind field explanation
kustomizations.kustomize.toolkit.fluxcd.io/v1beta2 .spec.dependsOn Items are references that can include a namespace
.spec.healthChecks Items are references that can include a namespace (note: these are accessed using impersonation)
.spec.sourceRef This is a reference that can include a namespace
.spec.targetNamespace This sets or overrides the namespace given in the top-most kustomization.yaml
helmreleases.helm.toolkit.fluxcd/v2beta1 .spec.dependsOn Items are references that can include a namespace
.spec.targetNamespace This gives the namespace into which a Helm chart is installed (note: using impersonation)
.spec.storageNamespace This gives the namespace in which the record of a Helm install is created (note: using impersonation)
.spec.chart.spec.sourceRef This is a reference (in the created HelmChart object) that can include a namespace
alerts.notification.toolkit.fluxcd.io/v1beta2 .spec.eventSources Items are references that can include a namespace
receivers.notification.toolkit.fluxcd.io/v1beta2 .spec.resources Items in this field are references that can include a namespace
imagepolicies.image.toolkit.fluxcd.io/v1beta1 .spec.imageRepositoryRef This reference can include a namespace[1]

[1] This particular cross-namespace reference is subject to additional access control; see "Access control for cross-namespace references" below.

Note that the field .spec.sourceRef of imageupdateautomation.image.toolkit.fluxcd.io does not include a namespace.

Access control for cross-namespace references

In v0.24, an ImagePolicy object can refer to a ImageRepository object in another namespace. Unlike most cross-namespace references, the controller processing ImagePolicy objects applies additional access control, as given in the referenced ImageRepository: the field .spec.accessFrom grants access to the namespaces selected therein. Access is denied unless granted.

Security considerations

Impersonation is optional

Flux does not insist on a service account to be supplied in Kustomization and HelmRelease specifications, and the default is to use the controller's service account. That means a user with the ability to create either of those objects can trivially arrange for a configuration to be applied with the controller service account, which in the default deployment of Flux will have cluster-admin bound to it. This represents a privilege escalation vulnerability in the default deployment of Flux. To guard against it, an admission controller can be used to make the .spec.serviceAccountName field mandatory; an example which uses Kyverno is given in the multi-tenancy implementation.

Cross-namespace references side-step namespace isolation

HelmRelease and Kustomization objects can refer to GitRepository, HelmRepository, or Bucket (collectively "sources") in any other namespace. The referenced objects are accessed through the controller's service account, which by default has cluster-admin bound to it. This means all sources in a cluster are by default usable as a synced configuration, from any namespace. To restrict access, an admission controller can be used to block cross-namespace references; the example using Kyverno from above also does this.

References

  • CVE-2021-41254 "Privilege escalation to cluster admin on multi-tenant environments" was fixed in flux2 v0.15.0.