Skip to content

feat: accept the toolbox edge token and route the CLI through bearer-preserving middlewares - #63

Merged
venkatamutyala merged 2 commits into
mainfrom
feat/cli-sso-through-oauth2-proxy
Sep 5, 2026
Merged

feat: accept the toolbox edge token and route the CLI through bearer-preserving middlewares#63
venkatamutyala merged 2 commits into
mainfrom
feat/cli-sso-through-oauth2-proxy

Conversation

@venkatamutyala

@venkatamutyala venkatamutyala commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Warning

Deploy the GlueOps platform chart before this on an upgrade. This template now references oauth2-with-redirect-bearer and oauth2-api, which GlueOps/platform-helm-chart-platform#1485 creates. The tenant README's order installs ArgoCD at step 2 and the platform chart at step 4 — the wrong way round here. Traefik drops a router whose middleware is missing, so argocd.<domain> answers 404 for the browser UI as well as the CLI until the platform chart lands. Fail-closed, not an auth bypass, and it self-heals — but it is an avoidable outage. See GlueOps/terraform-module-cloud-multy-prerequisites#720.

Ports the argocd.yaml changes that make the argocd CLI usable through oauth2-proxy, tested live on nonprod.jupiter.onglueops.rocks (the captain repo carries the rendered equivalent of exactly this diff, applied at argocd helm revision 6).

What changes

allowedAudiences: [argocd, toolbox] — ArgoCD verifies every token against Dex and, by default, accepts only aud: argocd. Adding toolbox lets the edge token developers mint from the public toolbox Dex client authenticate to ArgoCD directly. ⚠️ The setting replaces the default audience check rather than extending it: argocd must stay in the list or browser UI login breaks for everyone.

Middleware swaps on the two Ingresses — the old chains list authorization in forwardauth's authResponseHeaders, which Traefik applies as an unconditional req.Header.Del (oauth2-proxy never returns that header, so it only ever strips the caller's token):

route before after
/ (UI + root gRPC-web paths) oauth2-with-redirect oauth2-with-redirect-bearer — still redirects browsers to login, leaves the CLI's bearer intact
/api oauth2-no-redirect oauth2-api — same auth, 401 instead of an HTML redirect

Nothing is exempted from forwardauth; browser behaviour is unchanged (browsers never send Authorization).

Using it

./toolbox up <captain-domain>       # prints a URL to approve with GitHub
./toolbox argocd app list

GlueOps/toolbox is the supported path.

Correcting an earlier version of this description, which said to run export ARGOCD_AUTH_TOKEN=$(glueops-token); argocd app list --grpc-web. That does not work, and glueops-token does not exist anywhere in the org (the command is toolbox-token).

The token has to travel in two headers, because each side reads only its own:

header read by
ARGOCD_AUTH_TOKEN Token: <jwt> ArgoCD
--header "Authorization: Bearer <jwt>" Authorization: oauth2-proxy

ARGOCD_AUTH_TOKEN is carried as gRPC metadata under the key token (apiclient.go:60, :516), and --grpc-web copies metadata to headers verbatim — so the edge sees no Authorization, returns 401, the errors plugin turns that into a 302, and the CLI follows it to Dex and parses HTML as a gRPC frame:

rpc error: code = Unknown desc = unexpected EOF

Send only the header and you clear the edge with Token: empty, so ArgoCD answers Unauthenticated: no session information. toolbox sets both, fresh per invocation.

Known rough edge

On the / route, oauth2-with-redirect-bearer still chains the errors-redirect plugin, which rewrites 401–403 into a 302. When the Dex token itself has expired, the CLI therefore gets HTML instead of a clean 401 — the same class of problem #1485 fixes for OpenBao's /v1. /api is unaffected (oauth2-api has no errors plugin).

Backend responses are not affected: ArgoCD serves gRPC-web through grpcweb.WrapServer, and grpc-go reports RPC errors as HTTP 200 with a Grpc-Status trailer, which is outside the plugin's 401-403 range. So an expired ArgoCD token or an RBAC denial reaches the CLI as a proper gRPC status. Only the edge's own 401 is rewritten.

A tighter fix, if this proves annoying in practice, is an IngressRoute matching Content-Type: application/grpc-web+proto at priority > 10 and routing it through oauth2-api.

Dependency

The middlewares and the toolbox Dex client come from GlueOps/platform-helm-chart-platform#1485 — see the warning at the top.

Follow-up

🤖 Generated with Claude Code

https://claude.ai/code/session_01TrpnuCduw2KivngVRQmnG7

…preserving middlewares

Ports the argocd.yaml changes that let the argocd CLI work through oauth2-proxy:

- allowedAudiences [argocd, toolbox]: a developer's edge token (minted from the
  public "toolbox" Dex client) authenticates to ArgoCD directly via
  ARGOCD_AUTH_TOKEN, with no loopback callback. The setting REPLACES the default
  audience check rather than extending it, so "argocd" must stay listed or
  browser UI login breaks.

- oauth2-with-redirect-bearer on "/": ArgoCD serves gRPC-web at root paths, so
  this route needs a login redirect for browsers AND the caller's Authorization
  header left intact for CLIs. The old chain unconditionally stripped it.

- oauth2-api on "/api": authenticated the same, but answers 401 instead of an
  HTML redirect, which is what a CLI can act on.

Requires the middlewares and Dex client from
GlueOps/platform-helm-chart-platform#1485.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NiwgsqcQ4JikhFYj4NHEjM
…straint (#64)

Two comment corrections, no behaviour change.

The audience comment credited the "toolbox" Dex client to GlueOps/toolbox. The
client is created by platform-helm-chart-platform; GlueOps/toolbox is the CLI
that mints and presents the token. Also record that the token has to travel in
BOTH headers - ARGOCD_AUTH_TOKEN becomes "Token:" for ArgoCD, and oauth2-proxy
reads only a separate "Authorization: Bearer". Sending just the env var, as this
PR's own description did, gets a login redirect that the CLI reports as
"rpc error: unexpected EOF", which names nothing.

The Ingress now references middlewares this repo does not create. The documented
upgrade order in the tenant README deploys ArgoCD (step 2) before the platform
chart (step 4), so on an existing cluster that is the wrong way round: Traefik
drops a router whose middleware is missing, and argocd.<domain> answers 404 for
the browser UI as well as the CLI until the platform chart lands. It is
fail-closed rather than an auth bypass, and self-heals, but nothing said so.


Claude-Session: https://claude.ai/code/session_01TrpnuCduw2KivngVRQmnG7

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the patch label Sep 5, 2026
@venkatamutyala
venkatamutyala merged commit de01b66 into main Sep 5, 2026
2 checks passed
@venkatamutyala
venkatamutyala deleted the feat/cli-sso-through-oauth2-proxy branch September 5, 2026 08:29
venkatamutyala added a commit to GlueOps/terraform-module-cloud-multy-prerequisites that referenced this pull request Sep 5, 2026
…ox (#720)

* docs: warn about the argocd/platform upgrade order and point at toolbox

Two additions to the tenant README template.

Step 2 now says to run step 4 first when upgrading. argocd.yaml is moving to
Traefik middlewares that the platform chart creates (GlueOps/docs-argocd#63,
GlueOps/platform-helm-chart-platform#1485), and the order prescribed here
installs ArgoCD before the platform chart. On an existing cluster that means the
Ingress references middlewares that do not exist yet; Traefik drops the router
rather than serving it unprotected, so argocd.<domain> answers 404 for the
browser UI as well as the CLI until step 4 lands. Fail-closed and self-healing,
but an avoidable outage that nothing warned about. Fresh clusters keep the
existing order - nothing is serving yet, and ArgoCD has to exist before the
platform chart's Applications can sync.

Step 5 listed four browser URLs and no way to use the platform from a terminal.
GlueOps/toolbox has shipped since v0.0.5 and is referenced nowhere a tenant would
look: a search of the org finds no mention outside the repo itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrpnuCduw2KivngVRQmnG7

* docs: the argocd 404 outlasts the helm upgrade, say so

"until step 4 completes" was optimistic. Step 4 runs helm upgrade on the platform
chart, which only creates the glueops-core-traefik-crds-and-middleware
Application; the middlewares themselves arrive when Argo CD syncs that
Application through its sync-waves. So the 404 window extends past the helm
command returning, and an operator watching for the upgrade to finish would
conclude the outage should already be over.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrpnuCduw2KivngVRQmnG7

* docs: pin the version constraints to the released tags

The ordering warning and the toolbox bullet were written before the dependencies
were tagged, so they described the constraint without saying which versions it
starts from - leaving an operator to work out whether it applied to them.

Now released, so name them:

  docs-argocd                v0.21.0  - argocd.yaml starts referencing the
                                        bearer-preserving middlewares
  glueops-platform           v0.79.0  - first release that ships them
  vault configuration module v0.15.0  - creates the OpenBao jwt roles `bao`
                                        logs in through

The toolbox bullet gains the same floors, including the vault module, since
`./toolbox bao ...` fails against a cluster whose OpenBao has no jwt mount and
nothing else would explain why.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TrpnuCduw2KivngVRQmnG7

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant