Compare commits

..

6 Commits

11 changed files with 935 additions and 25 deletions
+6 -3
View File
@@ -1,4 +1,4 @@
FROM node:25-alpine3.22 AS frontend-builder
FROM --platform=$BUILDPLATFORM node:25-alpine3.22 AS frontend-builder
WORKDIR /app/frontend
@@ -11,7 +11,10 @@ COPY frontend/ .
RUN npm run build
FROM golang:1.25.4-alpine3.22 AS backend-builder
FROM --platform=$BUILDPLATFORM golang:1.25.4-alpine3.22 AS backend-builder
ARG TARGETOS
ARG TARGETARCH
WORKDIR /app
@@ -31,7 +34,7 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o garage-ui .
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -a -installsuffix cgo -o garage-ui .
FROM alpine:3.22
+1 -1
View File
@@ -502,7 +502,7 @@ replicaCount: 2
image:
repository: noooste/garage-ui
tag: v0.0.4
tag: latest
garage:
endpoint: "http://garage.storage.svc.cluster.local:3900"
+1 -1
View File
@@ -194,7 +194,7 @@ type ClusterHealth struct {
KnownNodes int `json:"knownNodes"`
ConnectedNodes int `json:"connectedNodes"`
StorageNodes int `json:"storageNodes"`
StorageNodesUp int `json:"storageNodesOk"`
StorageNodesUp int `json:"storageNodesUp"`
Partitions int `json:"partitions"`
PartitionsQuorum int `json:"partitionsQuorum"`
PartitionsAllOk int `json:"partitionsAllOk"`
+1 -1
View File
@@ -1,7 +1,7 @@
---
services:
garage:
image: dxflrs/garage:v2.0.0
image: dxflrs/garage:v2.1.0
container_name: garage
volumes:
- ./garage.toml:/etc/garage.toml
+3 -2
View File
@@ -1,9 +1,10 @@
apiVersion: v2
name: garage-ui
description: A Helm chart for Garage UI - Web interface for Garage S3 object storage
icon: https://helm.noste.dev/garage.png
type: application
version: 0.1.3
appVersion: "v0.0.7"
version: 0.1.6
appVersion: "v0.0.10"
keywords:
- garage
- s3
+2 -2
View File
@@ -2,8 +2,8 @@
A Helm chart for deploying [Garage UI](https://github.com/Noooste/garage-ui), a modern web interface for managing [Garage](https://garagehq.deuxfleurs.fr/) distributed object storage systems.
[![Version](https://img.shields.io/badge/version-0.1.1-blue.svg)](Chart.yaml)
[![App Version](https://img.shields.io/badge/app%20version-v0.0.6-green.svg)](Chart.yaml)
[![Version](https://img.shields.io/badge/version-0.1.6-blue.svg)](Chart.yaml)
[![App Version](https://img.shields.io/badge/app%20version-v0.0.10-green.svg)](Chart.yaml)
## Table of Contents
+2
View File
@@ -8,4 +8,6 @@ data:
config.yaml: |
{{- $config := deepCopy .Values.config }}
{{- $_ := unset $config.garage "admin_token" }}
{{- $_2 := unset $config.auth.admin "password" }}
{{- $_3 := unset $config.auth.oidc "client_secret" }}
{{- $config | toYaml | nindent 4 }}
+24
View File
@@ -46,6 +46,30 @@ spec:
name: {{ include "garage-ui.fullname" . }}-admin-token
key: admin-token
{{- end }}
{{- if .Values.config.auth.oidc.enabled }}
- name: GARAGE_UI_AUTH_OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
{{- if .Values.config.auth.oidc.existingSecret.name }}
name: {{ .Values.config.auth.oidc.existingSecret.name }}
key: {{ .Values.config.auth.oidc.existingSecret.key }}
{{- else }}
name: {{ include "garage-ui.fullname" . }}-oidc-client-secret
key: client-secret
{{- end }}
{{- end }}
{{- if .Values.config.auth.admin.enabled }}
- name: GARAGE_UI_AUTH_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
{{- if .Values.config.auth.admin.existingSecret.name }}
name: {{ .Values.config.auth.admin.existingSecret.name }}
key: {{ .Values.config.auth.admin.existingSecret.key }}
{{- else }}
name: {{ include "garage-ui.fullname" . }}-admin-password
key: admin-password
{{- end }}
{{- end }}
{{- if .Values.livenessProbe.enabled }}
livenessProbe:
httpGet:
+28
View File
@@ -9,3 +9,31 @@ type: Opaque
data:
admin-token: {{ .Values.config.garage.admin_token | b64enc | quote }}
{{- end }}
---
{{- if and .Values.config.auth.admin.enabled (not .Values.config.auth.admin.existingSecret.name) }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "garage-ui.fullname" . }}-admin-password
labels:
{{- include "garage-ui.labels" . | nindent 4 }}
type: Opaque
data:
{{- if .Values.config.auth.admin.password }}
admin-password: {{ .Values.config.auth.admin.password | b64enc | quote }}
{{- else }}
admin-password: {{ randAlphaNum 32 | b64enc | quote }}
{{- end }}
{{- end }}
---
{{- if and .Values.config.auth.oidc.enabled (not .Values.config.auth.oidc.existingSecret.name) .Values.config.auth.oidc.client_secret }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "garage-ui.fullname" . }}-oidc-client-secret
labels:
{{- include "garage-ui.labels" . | nindent 4 }}
type: Opaque
data:
client-secret: {{ .Values.config.auth.oidc.client_secret | b64enc | quote }}
{{- end }}
+809
View File
@@ -0,0 +1,809 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Garage UI Helm Chart Values",
"description": "Configuration values for the Garage UI Helm chart deployment",
"type": "object",
"required": ["replicaCount", "image", "config"],
"properties": {
"replicaCount": {
"type": "integer",
"description": "Number of replica pods to run. Increase for high availability (recommended: 2-3 for production)",
"minimum": 1,
"default": 1
},
"image": {
"type": "object",
"description": "Docker image configuration",
"required": ["repository", "pullPolicy"],
"properties": {
"repository": {
"type": "string",
"description": "Container registry and image name",
"default": "noooste/garage-ui"
},
"pullPolicy": {
"type": "string",
"description": "Image pull policy",
"enum": ["Always", "IfNotPresent", "Never"],
"default": "IfNotPresent"
},
"tag": {
"type": "string",
"description": "Image tag to use (defaults to chart appVersion if empty)",
"default": ""
}
}
},
"imagePullSecrets": {
"type": "array",
"description": "Credentials for accessing private container registries",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
},
"default": []
},
"nameOverride": {
"type": "string",
"description": "Override the default chart name in resource names",
"default": ""
},
"fullnameOverride": {
"type": "string",
"description": "Override the full resource name (includes release name)",
"default": ""
},
"config": {
"type": "object",
"description": "Main application configuration",
"required": ["server", "garage", "auth", "cors", "logging"],
"properties": {
"server": {
"type": "object",
"description": "Server configuration",
"required": ["host", "port", "environment", "protocol"],
"properties": {
"host": {
"type": "string",
"description": "Network interface to bind to (0.0.0.0 for all interfaces)",
"default": "0.0.0.0"
},
"port": {
"type": "integer",
"description": "Port the application listens on",
"minimum": 1,
"maximum": 65535,
"default": 8080
},
"environment": {
"type": "string",
"description": "Deployment environment",
"enum": ["production", "development", "staging"],
"default": "production"
},
"domain": {
"type": "string",
"description": "Domain name for the application",
"default": "garage-ui.example.com"
},
"protocol": {
"type": "string",
"description": "Protocol for internal communication",
"enum": ["http", "https"],
"default": "http"
},
"root_url": {
"type": "string",
"description": "Full external URL for OAuth2 redirects (REQUIRED when OIDC is enabled)",
"pattern": "^https?://",
"default": "https://garage-ui.example.com"
}
}
},
"garage": {
"type": "object",
"description": "Garage S3 storage configuration",
"required": ["endpoint", "region", "admin_endpoint"],
"properties": {
"endpoint": {
"type": "string",
"description": "Garage S3 API endpoint",
"pattern": "^(https?://)?[a-zA-Z0-9.-]+(:[0-9]+)?$",
"default": "http://garage:3900"
},
"region": {
"type": "string",
"description": "S3 region name (can be any value for Garage)",
"default": "garage"
},
"admin_endpoint": {
"type": "string",
"description": "Garage Admin API endpoint",
"pattern": "^https?://",
"default": "http://garage:3903"
},
"admin_token": {
"type": "string",
"description": "Admin API bearer token (ignored if existingSecret is configured)",
"default": ""
},
"existingSecret": {
"type": "object",
"description": "Use an existing Kubernetes secret for the admin token",
"properties": {
"name": {
"type": "string",
"description": "Name of the existing secret containing the admin token",
"default": ""
},
"key": {
"type": "string",
"description": "Key within the secret that contains the admin token value",
"default": "admin-token"
}
}
}
}
},
"auth": {
"type": "object",
"description": "Authentication configuration (one or both methods can be enabled)",
"required": ["admin", "oidc"],
"properties": {
"admin": {
"type": "object",
"description": "Admin authentication settings (username/password)",
"required": ["enabled"],
"properties": {
"enabled": {
"type": "boolean",
"description": "Enable or disable admin authentication",
"default": false
},
"username": {
"type": "string",
"description": "Username for admin login",
"default": "admin"
},
"password": {
"type": "string",
"description": "Password for admin login (ignored if existingSecret is configured)",
"default": "changeme"
},
"existingSecret": {
"type": "object",
"description": "Use an existing Kubernetes secret for the admin password",
"properties": {
"name": {
"type": "string",
"description": "Name of the existing secret containing the admin password",
"default": ""
},
"key": {
"type": "string",
"description": "Key within the secret that contains the admin password value",
"default": "admin-password"
}
}
}
}
},
"oidc": {
"type": "object",
"description": "OpenID Connect (OIDC) configuration",
"required": ["enabled"],
"properties": {
"enabled": {
"type": "boolean",
"description": "Enable or disable OIDC authentication",
"default": false
},
"provider_name": {
"type": "string",
"description": "Display name of your OIDC provider",
"default": "Keycloak"
},
"client_id": {
"type": "string",
"description": "OAuth2 client ID registered with your OIDC provider",
"default": "garage-ui"
},
"client_secret": {
"type": "string",
"description": "OAuth2 client secret (ignored if existingSecret is configured)",
"default": "your-client-secret"
},
"existingSecret": {
"type": "object",
"description": "Use an existing Kubernetes secret for the client secret",
"properties": {
"name": {
"type": "string",
"description": "Name of the existing secret containing the client secret",
"default": ""
},
"key": {
"type": "string",
"description": "Key within the secret that contains the client secret value",
"default": "client-secret"
}
}
},
"scopes": {
"type": "array",
"description": "OAuth2/OIDC scopes to request during authentication",
"items": {
"type": "string"
},
"default": ["openid", "email", "profile"]
},
"issuer_url": {
"type": "string",
"description": "OIDC issuer URL (base URL for OIDC discovery)",
"pattern": "^https?://",
"default": "https://keycloak.example.com/realms/master"
},
"auth_url": {
"type": "string",
"description": "Authorization endpoint URL",
"pattern": "^https?://",
"default": "https://keycloak.example.com/realms/master/protocol/openid-connect/auth"
},
"token_url": {
"type": "string",
"description": "Token endpoint URL",
"pattern": "^https?://",
"default": "https://keycloak.example.com/realms/master/protocol/openid-connect/token"
},
"userinfo_url": {
"type": "string",
"description": "User info endpoint URL",
"pattern": "^https?://",
"default": "https://keycloak.example.com/realms/master/protocol/openid-connect/userinfo"
},
"skip_issuer_check": {
"type": "boolean",
"description": "Skip issuer validation (not recommended for production)",
"default": false
},
"skip_expiry_check": {
"type": "boolean",
"description": "Skip token expiry validation (not recommended for production)",
"default": false
},
"email_attribute": {
"type": "string",
"description": "Claim containing user's email address",
"default": "email"
},
"username_attribute": {
"type": "string",
"description": "Claim containing user's username/login ID",
"default": "preferred_username"
},
"name_attribute": {
"type": "string",
"description": "Claim containing user's display name",
"default": "name"
},
"role_attribute_path": {
"type": "string",
"description": "Path to roles in the OIDC token claims",
"default": "resource_access.garage-ui.roles"
},
"admin_role": {
"type": "string",
"description": "Role name that grants admin privileges",
"default": "admin"
},
"tls_skip_verify": {
"type": "boolean",
"description": "Skip TLS certificate verification (only for testing)",
"default": false
},
"session_max_age": {
"type": "integer",
"description": "Session validity duration in seconds",
"minimum": 60,
"default": 86400
},
"cookie_name": {
"type": "string",
"description": "Name of the session cookie",
"default": "garage_session"
},
"cookie_secure": {
"type": "boolean",
"description": "Only send cookie over HTTPS connections",
"default": true
},
"cookie_http_only": {
"type": "boolean",
"description": "Prevent JavaScript access to the cookie",
"default": true
},
"cookie_same_site": {
"type": "string",
"description": "SameSite cookie attribute for CSRF protection",
"enum": ["lax", "strict", "none"],
"default": "lax"
}
}
}
}
},
"cors": {
"type": "object",
"description": "CORS (Cross-Origin Resource Sharing) configuration",
"required": ["enabled"],
"properties": {
"enabled": {
"type": "boolean",
"description": "Enable or disable CORS",
"default": true
},
"allowed_origins": {
"type": "array",
"description": "List of allowed origins",
"items": {
"type": "string"
},
"default": ["*"]
},
"allowed_methods": {
"type": "array",
"description": "HTTP methods allowed in CORS requests",
"items": {
"type": "string",
"enum": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"]
},
"default": ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
},
"allowed_headers": {
"type": "array",
"description": "HTTP headers allowed in CORS requests",
"items": {
"type": "string"
},
"default": ["Origin", "Content-Type", "Accept", "Authorization"]
},
"allow_credentials": {
"type": "boolean",
"description": "Allow credentials in CORS requests (cannot be true when allowed_origins contains '*')",
"default": false
},
"max_age": {
"type": "integer",
"description": "Cache duration for CORS preflight responses in seconds",
"minimum": 0,
"default": 3600
}
}
},
"logging": {
"type": "object",
"description": "Logging configuration",
"required": ["level", "format"],
"properties": {
"level": {
"type": "string",
"description": "Log verbosity level",
"enum": ["debug", "info", "warn", "error"],
"default": "info"
},
"format": {
"type": "string",
"description": "Log output format",
"enum": ["json", "text"],
"default": "json"
}
}
}
}
},
"podAnnotations": {
"type": "object",
"description": "Annotations to add to the pod",
"additionalProperties": {
"type": "string"
},
"default": {}
},
"podSecurityContext": {
"type": "object",
"description": "Pod-level security context",
"properties": {
"runAsNonRoot": {
"type": "boolean",
"description": "Run containers as non-root user",
"default": true
},
"runAsUser": {
"type": "integer",
"description": "User ID to run containers as",
"minimum": 0,
"default": 1000
},
"fsGroup": {
"type": "integer",
"description": "Group ID for filesystem access",
"minimum": 0,
"default": 1000
}
}
},
"securityContext": {
"type": "object",
"description": "Container-level security context",
"properties": {
"allowPrivilegeEscalation": {
"type": "boolean",
"description": "Allow privilege escalation",
"default": false
},
"capabilities": {
"type": "object",
"properties": {
"drop": {
"type": "array",
"items": {
"type": "string"
},
"default": ["ALL"]
}
}
},
"readOnlyRootFilesystem": {
"type": "boolean",
"description": "Mount root filesystem as read-only",
"default": false
}
}
},
"service": {
"type": "object",
"description": "Kubernetes Service configuration",
"required": ["type", "port"],
"properties": {
"type": {
"type": "string",
"description": "Service type",
"enum": ["ClusterIP", "NodePort", "LoadBalancer"],
"default": "ClusterIP"
},
"port": {
"type": "integer",
"description": "Port the service listens on",
"minimum": 1,
"maximum": 65535,
"default": 80
}
}
},
"ingress": {
"type": "object",
"description": "Ingress configuration",
"required": ["enabled"],
"properties": {
"enabled": {
"type": "boolean",
"description": "Enable or disable ingress",
"default": false
},
"className": {
"type": "string",
"description": "Ingress class name",
"default": "nginx"
},
"annotations": {
"type": "object",
"description": "Additional annotations for the ingress",
"additionalProperties": {
"type": "string"
},
"default": {}
},
"hosts": {
"type": "array",
"description": "Hostname and path configuration",
"items": {
"type": "object",
"required": ["host"],
"properties": {
"host": {
"type": "string",
"description": "Hostname for the ingress"
},
"paths": {
"type": "array",
"items": {
"type": "object",
"required": ["path", "pathType"],
"properties": {
"path": {
"type": "string",
"description": "URL path"
},
"pathType": {
"type": "string",
"description": "Path type",
"enum": ["Prefix", "Exact", "ImplementationSpecific"]
}
}
}
}
}
},
"default": [
{
"host": "garage-ui.local",
"paths": [
{
"path": "/",
"pathType": "Prefix"
}
]
}
]
},
"tls": {
"type": "array",
"description": "TLS/SSL configuration",
"items": {
"type": "object",
"properties": {
"secretName": {
"type": "string",
"description": "Name of the TLS secret"
},
"hosts": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"default": []
}
}
},
"resources": {
"type": "object",
"description": "CPU and memory resource limits and requests",
"properties": {
"limits": {
"type": "object",
"description": "Maximum resources the container can use",
"properties": {
"cpu": {
"type": "string",
"description": "Maximum CPU cores",
"pattern": "^[0-9]+(m|[0-9]*\\.?[0-9]+)?$",
"default": "500m"
},
"memory": {
"type": "string",
"description": "Maximum memory",
"pattern": "^[0-9]+(Ki|Mi|Gi|Ti|Pi|Ei)?$",
"default": "512Mi"
}
}
},
"requests": {
"type": "object",
"description": "Guaranteed resources allocated to the container",
"properties": {
"cpu": {
"type": "string",
"description": "Guaranteed CPU",
"pattern": "^[0-9]+(m|[0-9]*\\.?[0-9]+)?$",
"default": "100m"
},
"memory": {
"type": "string",
"description": "Guaranteed memory",
"pattern": "^[0-9]+(Ki|Mi|Gi|Ti|Pi|Ei)?$",
"default": "128Mi"
}
}
}
}
},
"livenessProbe": {
"type": "object",
"description": "Liveness probe configuration",
"required": ["enabled"],
"properties": {
"enabled": {
"type": "boolean",
"description": "Enable or disable liveness probe",
"default": true
},
"httpGet": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Health check endpoint path",
"default": "/health"
},
"port": {
"type": "string",
"description": "Port name",
"default": "http"
}
}
},
"initialDelaySeconds": {
"type": "integer",
"description": "Wait time before starting liveness checks",
"minimum": 0,
"default": 30
},
"periodSeconds": {
"type": "integer",
"description": "How often to perform the probe",
"minimum": 1,
"default": 10
},
"timeoutSeconds": {
"type": "integer",
"description": "Maximum time to wait for probe completion",
"minimum": 1,
"default": 3
},
"failureThreshold": {
"type": "integer",
"description": "Consecutive failures before restarting",
"minimum": 1,
"default": 3
}
}
},
"readinessProbe": {
"type": "object",
"description": "Readiness probe configuration",
"required": ["enabled"],
"properties": {
"enabled": {
"type": "boolean",
"description": "Enable or disable readiness probe",
"default": true
},
"httpGet": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Readiness check endpoint path",
"default": "/health"
},
"port": {
"type": "string",
"description": "Port name",
"default": "http"
}
}
},
"initialDelaySeconds": {
"type": "integer",
"description": "Wait time before starting readiness checks",
"minimum": 0,
"default": 10
},
"periodSeconds": {
"type": "integer",
"description": "How often to perform the probe",
"minimum": 1,
"default": 5
},
"timeoutSeconds": {
"type": "integer",
"description": "Maximum time to wait for probe completion",
"minimum": 1,
"default": 3
},
"failureThreshold": {
"type": "integer",
"description": "Consecutive failures before marking as not ready",
"minimum": 1,
"default": 3
}
}
},
"serviceMonitor": {
"type": "object",
"description": "ServiceMonitor for Prometheus Operator",
"required": ["enabled"],
"properties": {
"enabled": {
"type": "boolean",
"description": "Enable or disable ServiceMonitor creation",
"default": false
},
"interval": {
"type": "string",
"description": "How often Prometheus should scrape metrics",
"pattern": "^[0-9]+(s|m|h)$",
"default": "30s"
},
"path": {
"type": "string",
"description": "Metrics endpoint path",
"default": "/api/v1/monitoring/metrics"
},
"labels": {
"type": "object",
"description": "Additional labels for the ServiceMonitor",
"additionalProperties": {
"type": "string"
},
"default": {}
}
}
},
"networkPolicy": {
"type": "object",
"description": "NetworkPolicy configuration",
"required": ["enabled"],
"properties": {
"enabled": {
"type": "boolean",
"description": "Enable or disable NetworkPolicy creation",
"default": false
},
"policyTypes": {
"type": "array",
"description": "Types of policies to enforce",
"items": {
"type": "string",
"enum": ["Ingress", "Egress"]
},
"default": ["Ingress", "Egress"]
}
}
},
"nodeSelector": {
"type": "object",
"description": "Node selector labels",
"additionalProperties": {
"type": "string"
},
"default": {}
},
"tolerations": {
"type": "array",
"description": "Tolerations for pod scheduling",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"operator": {
"type": "string",
"enum": ["Exists", "Equal"]
},
"value": {
"type": "string"
},
"effect": {
"type": "string",
"enum": ["NoSchedule", "PreferNoSchedule", "NoExecute"]
}
}
},
"default": []
},
"affinity": {
"type": "object",
"description": "Affinity rules for pod scheduling",
"default": {}
}
}
}
+58 -15
View File
@@ -62,6 +62,21 @@ config:
# Options: "production", "development", "staging"
environment: "production"
# Domain name for the application
# Example: "garage-ui.example.com"
domain: "garage-ui.example.com"
# Protocol for internal communication
# Options: "http", "https"
# Keep as "http" for internal Kubernetes communication (TLS termination at ingress)
protocol: "http"
# Full external URL for OAuth2 redirects and external links
# This is the public-facing URL users access
# Example: "https://garage-ui.example.com"
# REQUIRED when OIDC authentication is enabled
root_url: "https://garage-ui.example.com"
# ========================================
# Garage S3 Storage Configuration
# ========================================
@@ -106,30 +121,44 @@ config:
# ========================================
# Authentication Configuration
# ========================================
# You can enable one or both authentication methods
auth:
# Authentication mode
# Options:
# "none" - No authentication (open access - not recommended for production)
# "basic" - Simple username/password authentication
# "oidc" - OpenID Connect integration (recommended for production)
mode: "none"
# Basic Authentication Settings
# Only used when mode = "basic"
# Admin Authentication Settings
# Provides simple username/password protection
basic:
# Username for basic auth login
admin:
# Enable or disable admin authentication
# Set to true to enable username/password login
enabled: false
# Username for admin login
username: "admin"
# Password for basic auth login
# IMPORTANT: Change this default password immediately!
# Password for admin login
# NOTE: If existingSecret is configured, this value will be ignored
# Leave empty to auto-generate a random password (when existingSecret is not specified)
password: "changeme"
# Use an existing Kubernetes secret for the admin password (recommended for production)
# When configured, this takes precedence over the password value above
# The secret should contain a key with the admin password value
existingSecret:
# Name of the existing secret containing the admin password
# Leave empty to use the password value above or auto-generate
# Example: "admin-credentials"
name: ""
# Key within the secret that contains the admin password value
# Default: "admin-password"
key: "admin-password"
# OpenID Connect (OIDC) Configuration
# Only used when mode = "oidc"
# Integrates with identity providers like Keycloak, Auth0, Okta, etc.
# NOTE: When OIDC is enabled, server.root_url must be configured
# The OAuth2 redirect URL is automatically constructed as: {root_url}/auth/oidc/callback
# Make sure to register this callback URL in your OIDC provider settings
oidc:
# Enable/disable OIDC (must be true when mode = "oidc")
# Enable or disable OIDC authentication
# Set to true to enable OIDC login
enabled: false
# Display name of your OIDC provider
@@ -142,8 +171,22 @@ config:
# OAuth2 client secret registered with your OIDC provider
# IMPORTANT: Keep this secret secure! Consider using Kubernetes secrets
# NOTE: If existingSecret is configured, this value will be ignored
client_secret: "your-client-secret"
# Use an existing Kubernetes secret for the client secret (recommended for production)
# When configured, this takes precedence over the client_secret value above
# The secret should contain a key with the client secret value
existingSecret:
# Name of the existing secret containing the client secret
# Leave empty to use the client_secret value above instead
# Example: "oidc-client-secret"
name: ""
# Key within the secret that contains the client secret value
# Default: "client-secret"
key: "client-secret"
# OAuth2/OIDC scopes to request during authentication
# Standard scopes: openid (required), email, profile
# Add custom scopes as needed by your provider