Flux Web UI Config API

This document describes the declarative API for configuring the Flux Web UI server.

Overview

The Config API supports:

  • Base URL Configuration - The public URL of the web UI
  • Security Settings - Control over secure/insecure cookie behavior
  • Authentication - User authentication and authorization
    • Anonymous - All users share a single identity for Kubernetes RBAC
    • OAuth2/OIDC - Users authenticate via an OpenID Connect provider

A YAML configuration file defines the settings to be used by the web UI server. This file must be specified with --web-config=<path to file> when starting the server.

Example:

# /etc/flux-status-page/config.yaml
apiVersion: web.fluxcd.controlplane.io/v1
kind: Config
spec:
  baseURL: https://flux-web.example.com
  authentication:
    type: OAuth2
    oauth2:
      provider: OIDC
      clientID: <OIDC-CLIENT-ID>
      clientSecret: <OIDC-CLIENT-SECRET>
      issuerURL: https://dex.example.com

Config API

apiVersion: web.fluxcd.controlplane.io/v1
kind: Config
spec:

  # Base URL for constructing URLs for the web UI. Required when using OAuth2 authentication.
  baseURL: https://flux-web.example.com

  # If true, sets insecure behaviors such as HTTP cookie 'secure' field to false.
  # Use only for local development or testing.
  insecure: false # Optional, default is false.

  # Authentication configuration (optional)
  authentication:
    type: OAuth2 # Anonymous | OAuth2

    # Duration of user sessions. Default: One week.
    sessionDuration: 24h # Optional

    # Size of the user cache in number of users. Default: 100.
    userCacheSize: 200 # Optional

    # Anonymous authentication settings (when type=Anonymous)
    anonymous:
      username: some-user
      groups:
        - some-group

    # OAuth2 authentication settings (when type=OAuth2 and oauth2.provider=OIDC)
    oauth2:
      provider: OIDC
      clientID: flux-web-client-id
      clientSecret: flux-web-client-secret
      issuerURL: https://dex.example.com

Authentication

Authentication controls how users are identified and what Kubernetes RBAC permissions they have when accessing Flux resources through the web UI.

Anonymous

Setting the authentication to Anonymous assigns a fixed identity to all users accessing the web UI. All users share the same Kubernetes RBAC permissions based on the configured username and/or groups.

At least one of username or groups must be specified.

spec:
  authentication:
    type: Anonymous
    anonymous:
      username: flux-readonly-user
      groups:
        - flux-viewers

Note that anyone who can access the web UI will have the same permissions, so this mode is only suitable for environments where the UI is accessible to trusted users in a secure network.

OAuth2 Authentication

OAuth2 authentication integrates with external identity providers to authenticate users. Currently, only the OIDC (OpenID Connect) provider is supported.

When OAuth2 is configured, spec.baseURL must be set to enable proper redirect handling during the OAuth2 flow.

OIDC Provider

The OIDC provider authenticates users via an OpenID Connect identity provider (such as Dex, Keycloak, Okta, Auth0, or any OIDC-compliant provider). For this provider, RBAC permissions are derived from claims in the ID token issued by the identity provider. This means that even if groups/roles are revoked from the user, their access to the web UI will persist until the ID token expires. For production environments where immediate revocation is required, consider using very short-lived tokens if supported by your identity provider. Dex, for example, allows configuring the ID token lifetime.

spec:
  baseURL: https://flux-web.example.com
  authentication:
    type: OAuth2
    oauth2:
      provider: OIDC
      clientID: flux-web                          # Required: OAuth2 client ID
      clientSecret: flux-web-secret               # Required: OAuth2 client secret
      issuerURL: https://auth.example.com        # Required: OIDC issuer URL
      scopes:                                    # Optional: custom scopes to request instead of defaults
        - groups
        - email

The default scopes requested are openid, offline_access, profile, email and groups.

After successful authentication, the OIDC provider extracts user information from the ID token claims to create a user session. This session includes:

  • Profile information - Display name shown in the UI
  • Impersonation credentials - Username and groups used for Kubernetes RBAC

Claims Processing with CEL

The OIDC provider uses Common Expression Language (CEL) expressions to extract and validate information from ID token claims. This provides flexibility in mapping identity provider claims to Kubernetes RBAC identities.

References for writing CEL expressions:

Variables

Variables allow you to extract and transform claim values for reuse in other expressions. Variables can reference previously declared variables, enabling complex data transformations.

spec:
  authentication:
    type: OAuth2
    oauth2:
      provider: OIDC
      # ... omitted for brevity ...
      variables:
        - name: username
          expression: "claims.sub"
        - name: domain
          expression: "claims.email.split('@')[1]"
        - name: departments
          expression: "claims.groups.filter(g, g.startsWith('dept:')).map(g, g.substring(5))"
Validations

Validations enforce rules on claims and variables. Each validation is a CEL expression that must return true for authentication to succeed. If a validation fails, its message is returned as an error.

spec:
  authentication:
    type: OAuth2
    oauth2:
      provider: OIDC
      # ... omitted for brevity ...
      variables:
        - name: domain
          expression: "claims.email.split('@')[1]"
      validations:
        - expression: "variables.domain == 'example.com'"
          message: "email domain not allowed"
        - expression: "size(claims.groups) > 0"
          message: "user must belong to at least one group"
Profile

The profile configuration extracts display information for the UI.

spec:
  authentication:
    type: OAuth2
    oauth2:
      provider: OIDC
      # ... omitted for brevity ...
      profile:
        name: "claims.name"

Default: "has(claims.name) ? claims.name : (has(claims.email) ? claims.email : '')"

Impersonation

Impersonation configures how the authenticated user’s identity maps to Kubernetes RBAC. The username and groups extracted here are used for Kubernetes API impersonation when the user accesses Flux resources.

spec:
  authentication:
    type: OAuth2
    oauth2:
      provider: OIDC
      # ... omitted for brevity ...
      impersonation:
        username: "claims.email"
        groups: "claims.groups"

Defaults:

  • username: "has(claims.email) ? claims.email : ''"
  • groups: "has(claims.groups) ? claims.groups : []"

At least one of username or groups must result in a non-empty value.

Configuration Examples

Anonymous Read-Only Access

apiVersion: web.fluxcd.controlplane.io/v1
kind: Config
spec:
  authentication:
    type: Anonymous
    anonymous:
      username: flux-viewer
      groups:
        - flux-readonly

Basic OIDC Authentication

apiVersion: web.fluxcd.controlplane.io/v1
kind: Config
spec:
  baseURL: https://flux-web.example.com
  authentication:
    type: OAuth2
    oauth2:
      provider: OIDC
      clientID: flux-web
      clientSecret: my-client-secret
      issuerURL: https://dex.example.com

OIDC with Custom Session Duration

apiVersion: web.fluxcd.controlplane.io/v1
kind: Config
spec:
  baseURL: https://flux-web.example.com
  authentication:
    type: OAuth2
    sessionDuration: 8h
    userCacheSize: 500
    oauth2:
      provider: OIDC
      clientID: flux-web
      clientSecret: my-client-secret
      issuerURL: https://dex.example.com

OIDC with Domain Validation

This example restricts access to users with emails from a specific domain:

apiVersion: web.fluxcd.controlplane.io/v1
kind: Config
spec:
  baseURL: https://flux-web.example.com
  authentication:
    type: OAuth2
    oauth2:
      provider: OIDC
      clientID: flux-web
      clientSecret: my-client-secret
      issuerURL: https://dex.example.com
      variables:
        - name: domain
          expression: "claims.email.split('@')[1]"
      validations:
        - expression: "variables.domain == 'example.com'"
          message: "Only example.com emails are allowed"

OIDC with Group Transformation

This example extracts department groups from prefixed claim values and uses them for Kubernetes RBAC:

apiVersion: web.fluxcd.controlplane.io/v1
kind: Config
spec:
  baseURL: https://flux-web.example.com
  authentication:
    type: OAuth2
    oauth2:
      provider: OIDC
      clientID: flux-web
      clientSecret: my-client-secret
      issuerURL: https://dex.example.com
      scopes:
        - groups
        - email
      variables:
        - name: username
          expression: "claims.sub"
        - name: departments
          expression: "claims.groups.filter(g, g.startsWith('dept:')).map(g, g.substring(5))"
      impersonation:
        username: "variables.username"
        groups: "variables.departments"

OIDC with Multiple Validations

apiVersion: web.fluxcd.controlplane.io/v1
kind: Config
spec:
  baseURL: https://flux-web.example.com
  authentication:
    type: OAuth2
    oauth2:
      provider: OIDC
      clientID: flux-web
      clientSecret: my-client-secret
      issuerURL: https://dex.example.com
      variables:
        - name: email
          expression: "claims.email"
        - name: domain
          expression: "variables.email.split('@')[1]"
      validations:
        - expression: "variables.domain in ['example.com', 'corp.example.com']"
          message: "Email domain not allowed"
        - expression: "size(claims.groups) > 0"
          message: "User must belong to at least one group"
        - expression: "claims.email_verified == true"
          message: "Email must be verified"
      profile:
        name: "has(claims.name) ? claims.name : variables.email"
      impersonation:
        username: "variables.email"
        groups: "claims.groups"