argoproj / argo-cd

Declarative Continuous Deployment for Kubernetes
https://argo-cd.readthedocs.io
Apache License 2.0
17.91k stars 5.46k forks source link

[Enhancement Proposal][RFD] Integrating with Hierarchical Namespace Controller / Matching Namespace by label #19895

Open BronzeDeer opened 2 months ago

BronzeDeer commented 2 months ago

Summary

Provide label matching for namespaces in applications.namespaces, AppProject.spec.sourceNamespaces and AppProject.spec.destinations[].namespaces.

Primarily this will allow us to match on the tree-labels of the hierarchical-namespace-controller (HNC), which allows for fuller, but secure self-service around namespaces for empowered developers. It would also expressing the permission to deploy apps in certain additional namespace in a more visible and coherent way that maintains clean and automatically right-scoped RBAC, reducing load on argoCD and cluster operators

Motivation

Currently, as part of the apps-in-any-namespace pattern used to empower individual developer teams to work with minimal or no reliance on a cluster/argo-admin, we are relying on name-globbing to provide dynamism for matching future namespaces, which do not exist at time of configuration. This minimizes the issue where on-boarding of new teams requires an ArgoCD Admin to manually expand the list in the configuration of the argoCD controllers, and potentially creating new role bindings as well. Similarly, if a team wants to deploy to a new namespace (either for internal grouping, or security boundaries, or ephemeral environments), a platform operator has to create said namespace and then manually update the destinations defined in the AppProject. If certain common namespaces are requested and later deleted to remove the team's permissions, manually tracking that change back into relevant AppProjects is required to not leave a dangling permission that might allow the team to intentionally or unintentionally breach into a separate team's namespace if they later start using said commonly named namespace. Globbing allows us to minimize this churn by creating an implied hierarchy through a system of nested prefixes like "argocd-apps-", and "argocd-apps-team-a-", however this hierarchy is not represented in Kubernetes anywhere and relies on out-of-band transmission of information ("Oh, that didn't work, because you didn't prefix your namespace correctly, it's in the docs somewhere)

Allowing namespaces to be matched by label would allow for a much clearer association of the semantic connection between "ArgoCD will read Applications from here", "This AppProject can deploy applications here and have them picked up by ArgoCD" and "ArgoCD/This appProject can deploy here". and a namespace. It also avoids over-matching potentially unintended namespaces through careless globbing.

However, this concept becomes most powerful for developer self-service, when combined with the Hierarchical Namespace Controller (HNC), which allows certain empowered users to create a hierarchy of sub-namespaces in a namespace, without ever breaching the Kubernetes isolation boundary enforced by namespaces.

An ArgoCD + HNC setup could even minimize the permission that need to be granted to ArgoCD, which normally needs to run in cluster-mode to allow for management of not yet created namespaces. Such a setup could look like the following:

Example ArgoCD + HNC Setup

There are 4 relevant cluster roles, mainly used for namespaced rolebindings:

At cluster creation, a cluster-admin:

(Note that all but the optional clusterRole for cluster-wide resources can be replaced with a copy of the role into the relevant namespace, however this creates higher churn and is potentially less clear, but this would allow for truly namespaced, but dynamic ArgoCD permissions)

At this point, these settings do not need to be touched anymore. ArgoCD will automatically be able to deploy into all children of argocd-destination and read applications from all children of argocd-apps creation of sub-namespaces can be delegated via K8S RBAC as needed. When a new team joins, the administrator creates a subnamespace of argocd-apps, called team-a-apps and a subnamespace of "argocd-destination" called "team-a-destination". Finally they create an AppProject, with sourceNamespace label matching on team-a-apps.tree.hnc.x-k8s.io/depth and a destination matching on the tree label for the latter.

Now, if this configuration also needs no further touches, no matter how many namespaces team-a creates in their destination sub-hierarchy. If either team-a "top"-level namespace is removed, all their permissions vanish, and even if another namespace with the same name is created outside of the hierarchy, argoCD will not inherit K8s permissions on it, nor will apps be read from the app name-space since they now exist outside of the containing hierarchy.

In summary, the permission model is fully and explicitly defined as hierarchical relations and permission sub-sets that allow, once setup for teams to fully self-manage, including creating namespace sub-isolation for ephemeral environments.

Proposal

matchLabels: selectors are nothing new or spectacular api or codewise and well established patterns inside the kubernetes ecosystem, so their implementation would be rather straight forward. What I mainly want to discuss is whether this would allow unaware operators to create hard-to-forsee security problems through misconfiguration that might be unacceptable in ArgoCD.

I can see a few areas of potential concern that arise from the fundamental lifecycle difference between name matching and label matching. The name of a resource cannot ever change, as such, whether a specific namespace is captured by the existing model can be decided statically and without contacting kube-api-server. On the other hand, namespaces can gain and shed labels during the lifetime, which makes authorizing decisions for a certain namespace depend on the current state of the cluster. This means:

Note that if the HNC is installed, running and only tree-labels are used, it is impossible to gain access to an existing namespace without having the ability to update namespaces and also set the parentage of an existing namespace within HNC's RBAC, otherwise the controller will immediately reconcile the attempted label change to conform to the correct hierarchy.

I would be very glad to supply the necessary PR to make this a reality, especially because I would like to use this pattern in IDPs I am building/maintaining. First, however. I would like to know whether this change in the security/permission model for applications in any namespace is tenable at all.

I can see two approaches:

There are some other detail design considerations for example:

But I think they are secondary to whether the general enhancement is reasonable

andrii-korotkov-verkada commented 2 days ago

Prefix matching can be tricky. What if team B creates an app with a name for team A? How do we avoid them getting extra permissions?