Flyte 2 Devbox is available today to run a full Flyte backend and UI locally. Preview Flyte 2 for production, hosted on Union.ai

Set up local OIDC provider

Step 7 of the Kind deployment guide gates the console behind Traefik and oauth2-proxy, using Dex running inside the same kind cluster as the identity provider — so you can test the whole authentication flow with no cloud account and no real users. This page covers deploying Dex itself: do it after installing Traefik and before deploying oauth2-proxy.

For local testing only

Dex here uses in-memory storage and a static test password baked into its config. It is an IdP stand-in for development — never use this configuration anywhere real.

The issuer-URL problem

OIDC has one constraint that shapes the Dex setup: the issuer URL must be identical everywhere it’s seen.

  • oauth2-proxy (running in-cluster) reaches Dex over a Kubernetes service name.
  • Your browser reaches Dex to log in, and must land on the same issuer the token was minted for, or validation fails.

A service name like dex.flyte.svc.cluster.local isn’t resolvable from your browser; a localhost URL isn’t resolvable from inside the cluster. The fix is to serve Dex under the same host as Flyte (flyte.local) at a sub-path (/dex), and route to it through Traefik. One URL — http://flyte.local/dex — works from both sides.

Dex configuration

The issuer is the through-Traefik URL; the two static clients are oauth2-proxy (confidential, with a secret) and the Flyte CLI (public, for SDK login). staticPasswords gives you a login with no external user store.

The Dex Helm chart renders whatever you pass under its config value into a Secret and mounts it as config.yaml — so write the configuration nested under a top-level config: key in a values file:

# dex-values.yaml
config:
  issuer: http://flyte.local/dex

  storage:
    type: memory

  web:
    http: 0.0.0.0:5556

  oauth2:
    skipApprovalScreen: true        # auto-approve, no consent screen in dev

  staticClients:
    # oauth2-proxy — confidential client (matches the secret you pass to oauth2-proxy in step 7)
    - id: oauth2-proxy
      name: oauth2-proxy
      secret: oauth2-proxy-secret
      redirectURIs:
        - 'http://flyte.local/oauth2/callback'
        - 'https://flyte.local/oauth2/callback'   # console opened over TLS (websecure)

    # Flyte CLI — public client for SDK/CLI PKCE login
    - id: flytectl
      name: 'Flyte CLI'
      public: true
      redirectURIs:
        - 'http://localhost:53593/callback'

  enablePasswordDB: true
  staticPasswords:
    # login: [email protected] / password
    - email: "[email protected]"
      username: "admin"
      userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
      # bcrypt hash of the literal string "password" — see the note below
      hash: "$2a$10$wi77Jcsjw08l416Q4./OCu6qNvYMaNSvA3Jbo30QeyZAvq9b4BSRK"
hash must be a real bcrypt hash

Dex validates the hash at startup and crashes (CrashLoopBackOff) with malformed bcrypt hash: hashedSecret too short to be a bcrypted password if it isn’t a complete 60-character bcrypt string. The hash above is for password and is known-good — but verify length 60 before pasting (echo -n "$HASH" | wc -c); a char lost in transit looks fine and crashes Dex. To use a different password:

htpasswd -bnBC 10 "" 'your-password' | tr -d ':\n' | sed 's/^\$2y/\$2a/'

Install Dex

helm repo add dex https://charts.dexidp.io
helm repo update

helm install dex dex/dex -n flyte -f dex-values.yaml
Why not a ConfigMap volume mount

The chart already defines its own config volume, so mounting your own with --set volumes[0].name=config collides with it (Duplicate value: "config"). Passing the config under the chart’s config value, as above, is the supported path and avoids the clash.

Confirm Dex came up:

kubectl -n flyte rollout status deploy/dex
kubectl -n flyte get svc dex          # note the port (5556 by default)

Route the issuer path through Traefik

Add an ingress so http://flyte.local/dex reaches the Dex service. This is what makes the single issuer URL resolve from the browser:

# dex-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: dex
  namespace: flyte
spec:
  ingressClassName: traefik
  rules:
  - host: flyte.local
    http:
      paths:
      - path: /dex
        pathType: Prefix
        backend:
          service:
            name: dex
            port:
              number: 5556
kubectl apply -f dex-ingress.yaml

Check discovery works through the host path — this is the URL oauth2-proxy will fetch:

# (with "127.0.0.1 flyte.local" in /etc/hosts and Traefik reachable on the node port)
curl -s http://flyte.local/dex/.well-known/openid-configuration | head

A JSON document with "issuer":"http://flyte.local/dex" confirms Dex is reachable at the issuer it advertises.

Next step

With Dex up and its issuer routable, return to the Kind deployment guide and deploy oauth2-proxy pointed at http://flyte.local/dex.