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.