Argo CD RBAC and Authentication Methods: A Complete Configuration Guide

Argo CD implements role-based access control using Casbin policies stored in the argocd-rbac-cm ConfigMap, supporting both local users and SSO providers like OIDC/OAuth for authentication.

Argo CD (from the argoproj/argo-cd repository) delegates identity management to external providers while enforcing authorization through a lightweight, Kubernetes-native policy engine. Unlike platforms that maintain their own user databases, Argo CD relies on a stateless design where the argocd-rbac-cm ConfigMap holds the complete authorization policy, and authentication is handled either via local accounts defined in argocd-cm or federated SSO.

Architecture Overview

Policy Store and Casbin Enforcer

The authorization layer centers on the Enforcer struct defined in util/rbac/rbac.go (lines 27-40). This wrapper around the Casbin library loads three distinct policy sources: the built-in policy from assets/builtin-policy.csv (containing role:readonly and role:admin), the user-defined policy from the argocd-rbac-cm ConfigMap, and optional runtime policies for temporary overrides via EnforceRuntimePolicy.

Pattern Matching and Evaluation Logic

Policy evaluation supports two match modes controlled by policy.matchMode: glob (default, using github.com/gobwas/glob) or regex (using Go's regexp package). The SetMatchMode function (lines 103-111 in util/rbac/rbac.go) configures this behavior.

When evaluating requests, the enforce function (lines 400-426) follows strict precedence:

  1. Check the default role (policy.default)
  2. Invoke any custom claims enforcer for JWT tokens via ClaimsEnforcerFunc
  3. Execute the Casbin policy check where deny rules always override allow

Resources and Actions

Constants defined in util/rbac/rbac.go declare the supported resources and their actions:

  • applications: get, create, update, delete, sync, action, override
  • applicationsets: get, create, update, delete
  • clusters: get, create, update, delete
  • projects: get, create, update, delete
  • repositories: get, create, update, delete
  • accounts: get, update
  • extensions: invoke

Fine-grained control over sub-resources (e.g., update/*/Pod/*/*) is supported since v3.0.0, with an optional backward-compatibility flag (server.rbac.disableApplicationFineGrainedRBACInheritance).

Authentication Methods

Local Users

Local accounts are defined in the argocd-cm ConfigMap under the data.accounts map. Passwords use bcrypt hashing. These users can be assigned policies directly or mapped to groups using the g, <user>, <role> syntax.

Example local user configuration:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  accounts.alice: "$2a$10$..."  # bcrypt password

SSO and OIDC Integration

For enterprise authentication, Argo CD supports OIDC/OAuth providers. The token's federated_claims.user_id becomes the subject in policy checks, while group membership is extracted from configured scopes (default groups). The HTTP middleware in server/rbacpolicy/rbacpolicy.go invokes the Enforcer for each API request, passing the parsed JWT claims.

Example SSO policy mapping:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
data:
  policy.csv: |
    p, my-org:team-beta, applications, sync, my-project/*, allow
    g, my-org:team-beta, role:admin
  scopes: '[groups, email]'

JWT Claims Enforcer

A pluggable ClaimsEnforcerFunc can be registered via Enforcer.SetClaimsEnforcerFunc to inspect JWT claims before Casbin evaluation. This allows arbitrary logic such as time-bound access or custom claim validation.

func myClaimsEnforcer(claims jwt.Claims, rvals ...any) bool {
    m, _ := jwtutil.MapClaims(claims)
    return m["role"] == "dev"
}

enf.SetClaimsEnforcerFunc(myClaimsEnforcer)

Configuration Examples

Defining RBAC Policies in ConfigMap

The policy.csv field uses Casbin's standard format:

  • Group assignment: g, <user|group>, <role>
  • Permission: p, <subject>, <resource>, <action>, <object>, <effect>
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  # Grant every authenticated user read-only access by default

  policy.default: role:readonly
  
  # Custom policies

  policy.csv: |
    g, my-org:team-beta, role:admin
    g, alice@example.com, role:readonly
    p, role:admin, *, *, *, allow
    p, role:readonly, applications, get, *, allow

Validating Policies via CLI

The argocd admin settings rbac commands in cmd/argocd/commands/admin_settings_rbac.go provide validation without applying changes:


# Validate CSV syntax

argocd admin settings rbac validate --policy-file my-rbac.yaml

# Test specific permissions

argocd admin settings rbac can --subject alice@example.com \
    --resource applications --action sync --object myproj/*

Programmatic Policy Enforcement

Use the Enforcer API directly in Go applications:

import (
    "github.com/argoproj/argo-cd/v3/util/rbac"
    "k8s.io/client-go/kubernetes"
)

// Assuming kubernetes client `kc`
enf := rbac.NewEnforcer(kc, "argocd", "argocd-rbac-cm", nil)

// Load policies from ConfigMap
if err := enf.LoadPolicy(); err != nil {
    panic(err)
}

// Check if user "bob" can sync apps in project "demo"
allowed := enf.Enforce("bob", rbac.ResourceApplications, rbac.ActionSync, "demo/*")

Summary

  • Argo CD stores RBAC policies in the argocd-rbac-cm ConfigMap using Casbin CSV format with glob or regex matching modes
  • The Enforcer struct in util/rbac/rbac.go manages policy loading, claims enforcement, and evaluation via the enforce function
  • Authentication supports local users (stored in argocd-cm) and SSO/OIDC providers, with the federated_claims.user_idclaim becoming the subject
  • Policy evaluation follows the precedence: default role → custom claims enforcer → Casbin policy, where explicit deny rules always override allow
  • Built-in roles role:readonly and role:admin are defined in assets/builtin-policy.csv and can be extended via custom policies

Frequently Asked Questions

Where are Argo CD RBAC policies stored?

Policies reside in the argocd-rbac-cm ConfigMap within the Argo CD namespace. This includes the policy.csv definitions, the optional policy.default fallback role, and the policy.matchMode setting (glob or regex). The Enforcer struct in util/rbac/rbac.go watches this ConfigMap and reloads policies at runtime.

What is the difference between local users and SSO in Argo CD authentication?

Local users are defined directly in the argocd-cm ConfigMap with bcrypt-hashed passwords and exist only within the Argo CD instance. SSO users authenticate via external OIDC/OAuth providers; Argo CD receives a JWT where the federated_claims.user_id claim becomes the subject for RBAC checks, and groups are extracted from the configured scopes (default groups).

How does Argo CD handle deny versus allow policies?

According to the enforce function implementation in util/rbac/rbac.go (lines 400-426), explicit deny rules always take precedence over allow rules. If no deny rule matches, any matching allow rule grants access. The policy.default role applies only when no specific policy matches the subject.

Can I use regex instead of glob for policy matching?

Yes. Set policy.matchMode: regex in the argocd-rbac-cm ConfigMap. The default mode is glob, implemented using github.com/gobwas/glob, but regex mode uses Go's standard regexp package for more complex pattern matching. Configure this via the SetMatchMode function in the RBAC utility code.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →