Skip to content

Sign-in

KubeGlass can sign people in itself, with no proxy in front of it. Two auth modes do this:

  • oidc: people sign in with your OpenID Connect provider, and KubeGlass impersonates them on every Kubernetes call, so their RBAC applies.
  • token: people paste a Kubernetes bearer token, which KubeGlass sends to the API server as their own credential.

The other modes are impersonation, where a sign-in proxy such as OAuth2 Proxy sends the user in headers, and local, where nobody signs in. See Running for a team.

  1. Someone opens KubeGlass without a session and lands on the sign-in page, with one button: Sign in with your provider.
  2. KubeGlass sends the browser to the provider with the authorization code flow and PKCE (S256), a state and a nonce, and the redirect URI exactly as configured.
  3. The provider sends the browser back to /auth/callback. KubeGlass checks that the state belongs to this browser, exchanges the code for tokens, and checks the ID token: signature, issuer, audience, expiry and nonce.
  4. KubeGlass creates a session and sets an httpOnly cookie that holds only a random session ID. The browser returns to the page it started on.

The ID token, refresh token and identity stay on the server. When the ID token is about to expire, KubeGlass uses the refresh token to get a new one; if the provider refuses (the person was removed or disabled there), the session ends. Without a refresh token the session ends when the ID token does, and the next page asks the person to sign in again, which takes one click while they are still signed in at the provider.

Sign out in the user menu ends the KubeGlass session. If the provider supports RP-initiated logout (it lists an end_session_endpoint), KubeGlass then posts the sign-out to it, so the person is signed out there too, and the provider sends them back to the sign-in page.

Register KubeGlass at your provider as a web application (the sections below show where), with:

  • Redirect URI: KubeGlass’s address followed by /auth/callback, for example https://kubeglass.example.com/auth/callback, or https://tools.example.com/kubeglass/auth/callback when KubeGlass is served under a path.
  • Post-logout redirect URI: the same address followed by /sign-in, for providers that support signing out there.

Then install the chart with config.authMode=oidc. Keep the client secret in a Secret:

Terminal window
kubectl -n kubeglass create secret generic kubeglass-oidc --from-literal=client-secret='<client secret>'
kubectl -n kubeglass create secret generic kubeglass-session --from-literal=session-key="$(openssl rand -base64 32)"
values-oidc.yaml
config:
authMode: oidc
oidc:
issuerURL: https://dex.example.com
clientID: kubeglass
clientSecretRef:
name: kubeglass-oidc
scopes: "openid profile email groups offline_access"
usernameClaim: email
groupsClaim: groups
session:
keySecretRef:
name: kubeglass-session
ingress:
enabled: true
hosts:
- host: kubeglass.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: kubeglass-tls
hosts: [kubeglass.example.com]
Terminal window
helm upgrade --install kubeglass oci://ghcr.io/kubeglass/charts/kubeglass -n kubeglass -f values-oidc.yaml

oidc.redirectURL defaults to the first Ingress host with config.basePath and /auth/callback; set it when KubeGlass is reached another way. With neither, browser sign-in is off (see Bearer tokens only). The values and their environment variables:

Chart value Variable Default What it does
oidc.issuerURL KUBEGLASS_OIDC_ISSUER_URL The provider’s issuer; KubeGlass reads /.well-known/openid-configuration under it
oidc.clientID KUBEGLASS_OIDC_CLIENT_ID KubeGlass’s client ID
oidc.clientSecretRef KUBEGLASS_OIDC_CLIENT_SECRET none The client secret. Leave it out for a public client, which PKCE alone protects
oidc.redirectURL KUBEGLASS_OIDC_REDIRECT_URL the Ingress host The registered redirect URI. It must end in /auth/callback, after the base path if there is one
oidc.scopes KUBEGLASS_OIDC_SCOPES openid profile email Scopes asked for at sign-in. Add the one your provider gives refresh tokens for
oidc.usernameClaim KUBEGLASS_OIDC_USER_CLAIM email (binary: sub) The claim that names the user
oidc.usernamePrefix KUBEGLASS_OIDC_USERNAME_PREFIX none Put in front of the user name
oidc.groupsClaim KUBEGLASS_OIDC_GROUPS_CLAIM groups The claim that lists the groups
oidc.groupsPrefix KUBEGLASS_OIDC_GROUPS_PREFIX none Put in front of each group
oidc.providerName KUBEGLASS_OIDC_PROVIDER_NAME from the issuer The name on the sign-in button
oidc.audience KUBEGLASS_OIDC_AUDIENCE the client ID The audience a bearer token in an Authorization header must have
session.keySecretRef KUBEGLASS_SESSION_KEY generated The key that encrypts sessions in the data directory
session.idleTimeout KUBEGLASS_SESSION_MAX_AGE 4h A session nobody used for this long ends. Typing into a shell is use; a log stream or a watch isn’t
session.lifetime KUBEGLASS_SESSION_LIFETIME 24h Every session ends this long after sign-in

The NetworkPolicy the chart creates lets KubeGlass reach port 443 anywhere. If your provider runs in the cluster on another port, such as Dex on 5556, add an egress rule for it in networkPolicy.additionalEgress.

Behind an Ingress or a load balancer, set config.trustedProxies (KUBEGLASS_TRUSTED_PROXIES) to the ingress controller’s addresses, or the range its pods get them from. KubeGlass then takes each person’s address from X-Forwarded-For for its rate limits, sign-in’s included, and sees from X-Forwarded-Proto that the Ingress ends HTTPS, so it sends HSTS. Without it everyone counts as the ingress controller, in one limit, and KubeGlass logs a warning. In oidc mode it doesn’t make KubeGlass believe identity headers; it signs people in itself.

KubeGlass impersonates usernamePrefix plus the usernameClaim value, in the groups from groupsClaim, each with groupsPrefix. Write RoleBindings for those names:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: platform-edit
namespace: shop
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: edit
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: jane@example.com
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: platform

If your API server also accepts OIDC tokens from the same provider (for kubectl), use the same claims and prefixes as its --oidc-username-claim, --oidc-username-prefix, --oidc-groups-claim and --oidc-groups-prefix, so one set of bindings serves both. config.adminUsers and config.adminGroups use the same names.

Because KubeGlass impersonates with its own ServiceAccount, it refuses identities the API server reserves: a user name that starts with system:, the name local-user, and, with usernameClaim: email, a token whose email_verified is false. Groups that start with system:, such as system:masters, are dropped. Limit whom KubeGlass may impersonate with rbac.impersonation.resourceNames.

In Dex’s configuration, add KubeGlass as a static client:

staticClients:
- id: kubeglass
name: KubeGlass
secret: <client secret>
redirectURIs:
- https://kubeglass.example.com/auth/callback

Values: issuerURL is Dex’s issuer, scopes: "openid profile email groups offline_access", usernameClaim: email, groupsClaim: groups. The groups scope makes Dex include the groups from its connector, and offline_access gives a refresh token. Dex has no RP-initiated logout, so Sign out ends the KubeGlass session only.

  1. In your realm, Clients › Create client: type OpenID Connect, client ID kubeglass.
  2. Turn on Client authentication, and keep Standard flow on.
  3. Valid redirect URIs: https://kubeglass.example.com/auth/callback. Valid post logout redirect URIs: https://kubeglass.example.com/sign-in.
  4. Copy the secret from the Credentials tab into the kubeglass-oidc Secret.
  5. For groups, open the client’s dedicated scope (Client scopes › kubeglass-dedicated), add a mapper by configuration of type Group Membership with token claim name groups, and turn off Full group path so the groups come without a leading slash (platform).

Values: issuerURL: https://keycloak.example.com/realms/<realm>, scopes: "openid profile email", usernameClaim: email (or preferred_username), groupsClaim: groups. Keycloak returns a refresh token without extra scopes. Under the client’s Advanced settings you can require PKCE with the S256 method.

  1. Applications › Create App Integration: OIDC, Web Application.
  2. Grant types: Authorization Code and Refresh Token.
  3. Sign-in redirect URIs: https://kubeglass.example.com/auth/callback. Sign-out redirect URIs: https://kubeglass.example.com/sign-in.
  4. Assign the people or groups who may use KubeGlass, and copy the client ID and secret.
  5. For groups, open Security › API › Authorization Servers › default › Claims and add a claim named groups, included in the ID token, with value type Groups and a filter such as Matches regex .*.

Values: issuerURL: https://<your-org>.okta.com/oauth2/default, scopes: "openid profile email offline_access", usernameClaim: email, groupsClaim: groups.

  1. App registrations › New registration. Under Redirect URI choose Web and enter https://kubeglass.example.com/auth/callback.
  2. Under Authentication add https://kubeglass.example.com/sign-in as a second Web redirect URI, so signing out can return there.
  3. Certificates & secrets › New client secret, and copy its value.
  4. For groups, Token configuration › Add groups claim, choose Security groups, and for the ID token Group ID. The claim lists group object IDs. Someone in more groups than fit in a token (200) gets no groups claim; filter the groups to those assigned to the application in that case.

Values: issuerURL: https://login.microsoftonline.com/<tenant ID>/v2.0, scopes: "openid profile email offline_access", usernameClaim: oid, groupsClaim: groups. The oid claim is the user’s object ID, which doesn’t change; Microsoft advises against authorizing on preferred_username or email, which can. Bindings then name users by object ID.

  1. In the Google Cloud console, APIs & Services › Credentials › Create credentials › OAuth client ID, application type Web application.
  2. Authorized redirect URIs: https://kubeglass.example.com/auth/callback.

Values: issuerURL: https://accounts.google.com, scopes: "openid profile email", usernameClaim: email. Google’s ID tokens carry no groups, so bind roles to users. Google has no offline_access scope (don’t add it; Google refuses the sign-in) and no RP-initiated logout, so sessions last the ID token’s hour, after which the next page signs the person in again with one click.

To let in only your organization’s accounts, make the OAuth consent screen Internal (Google Workspace), and bind roles only to your domain’s addresses.

With config.authMode=token the sign-in page asks for a Kubernetes bearer token instead, for example:

Terminal window
kubectl -n team-a create token viewer --duration 8h

KubeGlass asks the API server who the token belongs to (a SelfSubjectReview sent with the token), and keeps the token in the session on the server. Requests go to the API server with that token and none of KubeGlass’s own credentials, so the token’s RBAC applies, and the chart leaves the impersonate rule out of KubeGlass’s ClusterRole. The token is only sent to the cluster it was checked against, the one KubeGlass runs in; other clusters answer token_other_cluster. A session that holds a JWT ends when the token expires.

Behind an Ingress, set config.trustedProxies to the ingress controller’s addresses, as for oidc mode (see Set it up), so that each person gets their own rate limit and KubeGlass sees the HTTPS the Ingress ends. It doesn’t make KubeGlass believe identity headers in token mode either.

A request with an Authorization: Bearer header needs no session. In oidc mode the token must be a JWT from the provider whose audience is oidc.audience (the client ID by default); KUBEGLASS_OIDC_REQUIRED_SCOPES can require scopes in it. In token mode it is a Kubernetes token, checked with the API server. Pass it to the MCP server with --token.

Without a redirect URI (oidc_redirect_url, or the chart’s oidc.redirectURL and no Ingress), oidc mode works as it did before browser sign-in: it needs only the issuer and the audience, and accepts requests with a bearer token, for example from a proxy in front that adds the header. KubeGlass logs one warning at startup, browser sign-in is off, naming what to set, and the sign-in page tells visitors without a token that sign-in isn’t set up. Releases that set the oidc variables with the chart’s extraEnv upgrade unchanged: the chart adds no oidc settings of its own while oidc.issuerURL is empty.

  • The cookie, kubeglass-auth (__Host-kubeglass-auth over HTTPS), is httpOnly, SameSite=Lax, and Secure whenever KubeGlass is reached over HTTPS. Under a base path its name ends with a short hash of the path. It holds a random 256-bit session ID and nothing else.
  • Sessions are stored in the data directory, sealed with AES-256-GCM under the session key, by a hash of their ID. With a PersistentVolumeClaim (persistence.existingClaim) people stay signed in across restarts; changing the key signs everyone out.
  • Requests that change something must come from KubeGlass’s own pages: the browser’s Sec-Fetch-Site (or Origin) must say same-origin, and the request must carry the session’s CSRF token in X-CSRF-Token. Pages from other origins in KUBEGLASS_CORS_ALLOWED_ORIGINS are trusted.
  • The sign-in itself is bound to the browser that started it, works once, and expires after 10 minutes. The page to return to must be a path on KubeGlass.
  • Codes, states and tokens are never written to the log, and tokens never go in a URL.
  • Keep one replica: sessions live in the one pod’s data directory.

The sign-in page says what went wrong, and the log has a Sign-in failed line from the login component with the reason:

Page says Look at
The sign-in took too long, or started in another tab or browser The person took over 10 minutes, or opened the callback in another browser. Signing in again works
Provider didn’t sign you in The provider refused: the person isn’t assigned to the application, or chose not to continue
Provider answered with an error The provider’s message is in the log. Often a redirect URI that isn’t registered exactly, or a scope it doesn’t know
KubeGlass couldn’t finish signing you in The token request failed: client ID, client secret, or a redirect URI that differs from the registered one
Provider sent an identity KubeGlass doesn’t accept The ID token failed a check: wrong audience, the user claim missing, an unverified email, or a reserved user name