Argo CD doesn’t actually enforce RBAC policies; it delegates that responsibility to Kubernetes itself.

Let’s see how this plays out. Imagine you’ve got a new developer, Alice, who needs to deploy applications into the dev namespace. You want her to be able to create, update, and delete Argo CD Application resources, but only within that dev namespace.

First, we need to tell Argo CD who Alice is. This is typically done through its authentication mechanisms. Argo CD can integrate with OIDC providers (like Auth0, Keycloak, Okta), LDAP, or basic auth. For this example, let’s assume Alice authenticates via OIDC and her user is mapped to a group called developers.

Now, for the actual RBAC. Argo CD uses a Role and RoleBinding (or ClusterRole and ClusterRoleBinding for cluster-wide access) to grant permissions.

Here’s the Role that defines what Alice can do within the dev namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: argocd-app-manager
  namespace: dev
rules:
- apiGroups: ["argoproj.io"]
  resources: ["applications"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

This Role is named argocd-app-manager and lives within the dev namespace. It grants permissions to Argo CD’s custom resource, applications (which is what an Argo CD Application resource is, under the hood), allowing the specified verbs: get, list, watch, create, update, patch, and delete.

Next, we need to bind this Role to Alice’s group. This is done with a RoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: argocd-dev-app-managers
  namespace: dev
subjects:
- kind: Group
  name: developers # This must match the group name from your OIDC/authentication provider
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: argocd-app-manager # The Role we defined above
  apiGroup: rbac.authorization.k8s.io

This RoleBinding, also in the dev namespace, links the developers group to the argocd-app-manager Role. When Alice, as part of the developers group, interacts with Argo CD to manage applications, Kubernetes will check if her group has been granted these permissions in the dev namespace.

So, when Alice logs into Argo CD and tries to create an Application pointing to the dev namespace, Argo CD makes an API call to the Kubernetes API server. The Kubernetes API server, using the RoleBinding, checks if the developers group has the create verb on applications resources in the dev namespace. If it does, the action is allowed. If she tries to create an application in the prod namespace, it will fail because there’s no RoleBinding granting her that permission there.

The surprising truth is that Argo CD itself doesn’t have any internal RBAC logic for its own resources like Application, AppProject, etc. It just translates your UI or CLI actions into Kubernetes API calls and relies entirely on Kubernetes RBAC to permit or deny them. This means you can use the full power of Kubernetes RBAC, including complex conditions and policies, to control access to Argo CD resources.

Consider AppProject. This is another custom resource managed by Argo CD, used to define project-level configurations like allowed source repositories and destination clusters. If you want to restrict which AppProject resources a user can manage, you’d create a Role and RoleBinding for appprojects (plural) just like we did for applications.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: argocd-project-manager
  namespace: dev # Or cluster-wide if you want to manage cluster-level AppProjects
rules:
- apiGroups: ["argoproj.io"]
  resources: ["appprojects"]
  verbs: ["get", "list", "watch", "create", "update", "delete"]

And the corresponding RoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: argocd-dev-project-managers
  namespace: dev # Or cluster-wide
subjects:
- kind: Group
  name: developers
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: argocd-project-manager
  apiGroup: rbac.authorization.k8s.io

This setup allows developers to manage their applications and projects within their designated namespaces.

A crucial detail is how Argo CD itself is configured to act as the user making these API calls. Argo CD runs as a set of Kubernetes deployments (e.g., argocd-server, argocd-repo-server). These deployments have ServiceAccounts associated with them. It’s the RBAC permissions granted to these ServiceAccounts that allow Argo CD to perform its core functions, such as syncing applications or creating/updating Kubernetes resources based on an Argo CD Application definition. For example, the argocd-server needs permissions to list and get applications, and the argocd-application-controller needs permissions to create, update, and delete Kubernetes resources in the target namespaces.

If you’re seeing errors like "forbidden" when Argo CD tries to sync an application, it’s almost always an issue with the RBAC permissions granted to the Argo CD controller’s ServiceAccount in the target cluster or namespace, not with the RBAC you’re trying to configure for your users.

The next hurdle you’ll likely encounter is understanding how to grant Argo CD itself permissions to deploy to multiple clusters.

Want structured learning?

Take the full Argocd course →