Argo Workflows doesn’t actually enforce RBAC on its own; it relies entirely on Kubernetes’ built-in RBAC system to control who can do what with your workflows.

Let’s see it in action. Imagine you have a Kubernetes cluster, and you want to give a specific user, dev-user, the ability to create and view workflows, but not delete them or modify anything else. This is where RBAC comes in.

First, you’ll need a ServiceAccount for Argo Workflows to run under. This is the identity your Argo controller will use within the cluster.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: argo-workflows-controller
  namespace: argo

Next, you’ll create a ClusterRole that defines the permissions Argo Workflows needs. This includes the ability to manage workflow resources, pods, and other related Kubernetes objects.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: argo-workflows-role
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log", "secrets", "configmaps", "namespaces"]
  verbs: ["create", "get", "list", "watch", "update", "patch", "delete"]
- apiGroups: ["argoproj.io"]
  resources: ["workflows", "workflowtemplates", "clusterworkflows", "clusterworkflowtemplates"]
  verbs: ["create", "get", "list", "watch", "update", "patch", "delete"]
- apiGroups: ["argoproj.io"]
  resources: ["workflows/status"]
  verbs: ["update", "patch"]
- apiGroups: ["batch"]
  resources: ["jobs"]
  verbs: ["create", "get", "list", "watch", "update", "patch", "delete"]

Then, you bind this ClusterRole to the argo-workflows-controller ServiceAccount using a ClusterRoleBinding. This grants the Argo controller the defined permissions cluster-wide.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: argo-workflows-controller-binding
subjects:
- kind: ServiceAccount
  name: argo-workflows-controller
  namespace: argo
roleRef:
  kind: ClusterRole
  name: argo-workflows-role
  apiGroup: rbac.authorization.k8s.io

Now, let’s consider granting specific user permissions. To allow dev-user to create and view workflows in the argo namespace, you’d create a Role and a RoleBinding.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: argo-workflow-developer
  namespace: argo
rules:
- apiGroups: ["argoproj.io"]
  resources: ["workflows"]
  verbs: ["create", "get", "list", "watch"]
- apiGroups: ["argoproj.io"]
  resources: ["workflows/status"]
  verbs: ["get"]
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: argo-workflow-developer-binding
  namespace: argo
subjects:
- kind: User
  name: dev-user # This would be the actual username from your authentication provider
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: argo-workflow-developer
  apiGroup: rbac.authorization.k8s.io

This setup means that when dev-user uses kubectl or the Argo UI to interact with workflows, Kubernetes checks their permissions against these RBAC rules. They can create a new workflow, list existing ones, and see their status, but attempting to delete a workflow would result in a "forbidden" error because the delete verb isn’t included in their Role.

The most surprising truth about Argo Workflows RBAC is that it doesn’t have its own internal RBAC system; it’s a pure delegation to Kubernetes RBAC. This means that any Kubernetes authentication and authorization mechanism you already have in place (like OIDC, certificates, or service accounts) works seamlessly with Argo Workflows without any extra configuration on Argo’s part.

The next hurdle you’ll likely encounter is managing secrets for workflow steps, which requires careful RBAC configuration for the secrets resource.

Want structured learning?

Take the full Argo-workflows course →