argoproj / argoproj/argo-workflows

Allow SSO ServiceAccount to override the UI default namespace per tenant

Open
#16,153 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
17k
Forks
3.7k
Avg merge
1d 20h
Merged PRs (30d)
138

Description

# Summary
Allow the ServiceAccount matched by SSO RBAC to declare the UI's default landing namespace via a new `workflows.argoproj.io/default-namespace` annotation. When present, the gatekeeper substitutes the annotation's value for `ServiceAccountNamespace` in the claims returned by `/api/v1/userinfo`, so the UI lands the user in their tenant namespace instead of the install namespace. Opt-in: absent annotation preserves current behavior.
Today, the UI's "current namespace" for a freshly logged-in SSO user is initialized from the matched SSO-mapping ServiceAccount's own `metadata.namespace`. SSO-mapping ServiceAccounts must live in the install namespace (Argo only walks that namespace when matching `rbac-rule` annotations against claims), so in a multi-tenant install where users have permissions only in their **tenant** namespace, the UI lands on the install namespace where the user has no permissions and every list call returns 403.
## Use Cases
Multi-tenant Argo Server installs where SSO maps each user/group to a tenant ServiceAccount in the install namespace, but the user's actual workflow permissions live in a **separate tenant namespace**. Today the UI lands every SSO user on the install namespace, producing an empty list and confusing 403s on first login.
With this change, an admin annotates each tenant's SSO-mapping ServiceAccount once:
```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: alice
namespace: argo # install ns — where SSO matching happens
annotations:
workflows.argoproj.io/rbac-rule: "preferred_username == 'alice'"
workflows.argoproj.io/rbac-rule-precedence: "10"
workflows.argoproj.io/default-namespace: "argo-jobs-alice"
and alice lands in argo-jobs-alice immediately after SSO login, the Workflows list loads, and the ClusterWorkflowTemplate details page works without cluster-admin.
Server change
- New annotation workflows.argoproj.io/default-namespace on the SSO-mapped ServiceAccount.
- Read in server/auth/sso gatekeeper after RBAC matching; absent annotation preserves current behavior (the SA's own namespace is used).
- Surfaced in /api/v1/userinfo as serviceAccountNamespace, which the UI already consumes as userNamespace.
- The annotation value is treated as a literal namespace name. Argo Server does not validate that the namespace exists or that the user has permissions there — it only changes what the UI defaults to. The user's actual access is still governed by their RoleBindings in the target namespace, so this does not expand any user's authorization.
UI fixes required for the annotation to take effect on first login
Three pre-existing UI bugs prevent the new claim from being honored cleanly. They are fixed alongside the server change:
1. getCurrentNamespace() empty-string shadowing. The helper uses ?? to fall back from the persisted current_namespace, which preserves an empty string. A user who ever loaded the all-namespaces view writes current_namespace = "" to localStorage, shadowing both the new SA-annotation default and the legacy SA-namespace default forever after. Switch to || so empty string falls through.
2. WorkflowsList ignores userNamespace. Component initializes from getNamespace(match.params.namespace) || "", which honors managedNamespace only and ignores the userNamespace seeded by app-router from /userinfo. After OAuth redirect to bare /workflows this leaves the page on namespace="" and yields 403 for tenant users. Add getCurrentNamespace() to the fallback chain.
3. ClusterWorkflowTemplateDetails cross-namespace list. Component fires services.workflows.list('') to populate the "workflows that reference this template" panel. Empty namespace means cross-namespace listing server-side, which only cluster-admins are authorized for, so every CWT details page returns 403 for tenant SSO users. Use the same getNamespaceWithDefault() fallback chain (current → userNamespace → managedNamespace → default); only cluster-admins lose cross-namespace visibility on this one panel, which they retain elsewhere.
The behavior is fully opt-in (no annotation = current behavior) and does not expand any user's authorization — it only changes the namespace the UI defaults to within the user's existing RBAC scope.

Contributor guide

Open the contributing guide

Research direction

Start at the SSO gatekeeper and the /api/v1/userinfo response, then trace getCurrentNamespace(), WorkflowsList, and ClusterWorkflowTemplateDetails in the UI. Implement the opt-in default-namespace behavior while preserving the existing fallback when the annotation is absent, and update the three named UI fallback paths so tenant users land in an authorized namespace without changing RBAC.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, kubernetes
Domain
authentication, authorization, backend, frontend
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.