argoproj/argo-workflows · error

failed to evaluate rule: %w

Error message

failed to evaluate rule: %w

What it means

getServiceAccount evaluates each ServiceAccount's workflows.argoproj.io/rbac-rule annotation as a bool expression (argoexpr.EvalBool) against the OIDC claims. This error is returned when the rule expression is invalid: bad syntax, references to fields not present in the claims JSON, or wrong types (e.g. comparing a string to a number). Because the code returns on the first failing rule rather than skipping it, one broken rule annotation can break SSO login for every user, even those who would match a later, valid rule.

Source

Thrown at server/auth/gatekeeper.go:254

	}
	var serviceAccounts []*corev1.ServiceAccount
	for _, serviceAccount := range list {
		_, ok := serviceAccount.Annotations[common.AnnotationKeyRBACRule]
		if !ok {
			continue
		}
		serviceAccounts = append(serviceAccounts, serviceAccount)
	}
	sort.Slice(serviceAccounts, func(i, j int) bool { return precedence(serviceAccounts[i]) > precedence(serviceAccounts[j]) })
	for _, serviceAccount := range serviceAccounts {
		rule := serviceAccount.Annotations[common.AnnotationKeyRBACRule]
		v, err := jsonutil.Jsonify(claims)
		if err != nil {
			return nil, fmt.Errorf("failed to marshall claims: %w", err)
		}
		allow, err := argoexpr.EvalBool(rule, v)
		if err != nil {
			return nil, fmt.Errorf("failed to evaluate rule: %w", err)
		}
		if !allow {
			continue
		}
		return serviceAccount, nil
	}
	return nil, fmt.Errorf("no service account rule matches")
}

func (s *gatekeeper) canDelegateRBACToRequestNamespace(req any) bool {
	if s.namespaced || os.Getenv("SSO_DELEGATE_RBAC_TO_NAMESPACE") != "true" {
		return false
	}
	namespace := getNamespace(req)
	return len(namespace) != 0 && s.ssoNamespace != namespace
}

func (s *gatekeeper) getClientsForServiceAccount(ctx context.Context, claims *authTypes.Claims, serviceAccount *corev1.ServiceAccount) (*servertypes.Clients, error) {

View on GitHub (pinned to 35bff19146)

Solutions

  1. Fix the rbac-rule annotation on the offending ServiceAccount so it is a valid expr expression, e.g. `"workflows.argoproj.io/rbac-rule": "email.endsWith('@example.com')"` with proper YAML quoting.
  2. Verify claim field names/types by logging the claims or testing a rule like `true`; replace direct string/number comparisons with matching types (e.g. `sub == "user@x"` not `sub == 123`).
  3. Quote the whole rule in YAML (single quotes) so special chars aren't parsed by YAML; then re-check with `kubectl get sa -o yaml`.
  4. Test locally: `argo server --auth-mode sso` with RBAC enabled and inspect the 'failed to perform RBAC authorization' log line for the wrapped cause.

Example fix

// before: broken annotation (unquoted, missing dot-escape, type mismatch)
metadata:
  annotations:
    workflows.argoproj.io/rbac-rule: email.endsWith(@example.com) && sub == 123
// after
metadata:
  annotations:
    workflows.argoproj.io/rbac-rule: 'email.endsWith("@example.com") && sub == "123"'
Defensive patterns

Strategy: validation

Validate before calling

// validate rbac-rule annotations before applying
for sa in $(kubectl -n argo get sa -o name); do
  rule=$(kubectl -n argo get $sa -o jsonpath='{.metadata.annotations.workflows\.argoproj\.io/rbac-rule}')
  [ -n "$rule" ] && echo "$sa: $rule"   # review quoting/claim names
done

Try / catch

// operator-side: the server converts this to PermissionDenied
if st, ok := status.FromError(err); ok && st.Code() == codes.PermissionDenied {
    log.Printf("SSO RBAC denied; check rbac-rule annotations: %v", st.Message())
}

Prevention

When it happens

Trigger: An SSO request with RBAC enabled hits a ServiceAccount whose rbac-rule annotation is not a syntactically valid expr-lang expression, or references claim keys/values that don't exist or have mismatched types (e.g. `sub == 123` when sub is a string, unknown identifiers like `groups` when the IDP doesn't emit them).

Common situations: Typos in the rbac-rule annotation (yaml quoting stripped operators), rules copied from docs that use claims your OIDC provider doesn't provide (e.g. email for IDPs that hide emails), numeric-vs-string comparisons, and unquoted special characters in YAML.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/630b4a98abf204e2. Report an issue: GitHub.