feat: add initial Helm chart for Garage UI deployment

Signed-off-by: Noooste <83548733+Noooste@users.noreply.github.com>
This commit is contained in:
Noooste
2025-12-19 19:24:40 +01:00
parent b747e4dee2
commit 067e00b474
12 changed files with 1259 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
+19
View File
@@ -0,0 +1,19 @@
apiVersion: v2
name: garage-ui
description: A Helm chart for Garage UI - Web interface for Garage S3 object storage
type: application
version: 0.1.0
appVersion: "latest"
keywords:
- garage
- s3
- object-storage
- ui
- dashboard
- web-ui
home: https://github.com/Noooste/garage-ui
sources:
- https://github.com/Noooste/garage-ui
maintainers:
- name: Noooste
kubeVersion: ">=1.19.0-0"
+396
View File
@@ -0,0 +1,396 @@
# Garage UI Helm Chart
A Helm chart for deploying Garage UI, a web interface for [Garage](https://garagehq.deuxfleurs.fr/) S3 object storage.
## Introduction
This chart bootstraps a Garage UI deployment on a Kubernetes cluster using the Helm package manager. Garage UI provides a user-friendly web interface for managing your Garage S3 storage, including buckets, objects, users, and cluster monitoring.
## Prerequisites
- Kubernetes 1.19+
- Helm 3.0+
- A running Garage S3 instance with Admin API access
## Installing the Chart
To install the chart with the release name `my-garage-ui`:
```bash
helm install my-garage-ui ./helm/garage-ui
```
The command deploys Garage UI on the Kubernetes cluster with default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation.
## Uninstalling the Chart
To uninstall/delete the `my-garage-ui` deployment:
```bash
helm uninstall my-garage-ui
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
## Parameters
### Common Parameters
| Parameter | Description | Default |
|-----------|-------------|---------|
| `replicaCount` | Number of Garage UI replicas | `1` |
| `image.repository` | Garage UI image repository | `noooste/garage-ui` |
| `image.tag` | Garage UI image tag (overrides Chart appVersion) | `""` |
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
| `imagePullSecrets` | Image pull secrets | `[]` |
| `nameOverride` | Override chart name | `""` |
| `fullnameOverride` | Override full resource names | `""` |
### Service Parameters
| Parameter | Description | Default |
|-----------|-------------|---------|
| `service.type` | Kubernetes service type | `ClusterIP` |
| `service.port` | Service port | `80` |
### Configuration Parameters
| Parameter | Description | Default |
|-----------|-------------|---------|
| `config` | Complete config.yaml content as multiline string | See `values.yaml` |
**Important:** The `config` parameter contains the entire application configuration including Garage endpoints, authentication settings, CORS, and logging. You must customize this section with your Garage S3 endpoints and admin token.
### Ingress Parameters
| Parameter | Description | Default |
|-----------|-------------|---------|
| `ingress.enabled` | Enable ingress controller resource | `false` |
| `ingress.className` | Ingress class name | `nginx` |
| `ingress.annotations` | Ingress annotations | `{}` |
| `ingress.hosts` | Ingress hosts configuration | See `values.yaml` |
| `ingress.tls` | Ingress TLS configuration | `[]` |
### Monitoring Parameters
| Parameter | Description | Default |
|-----------|-------------|---------|
| `serviceMonitor.enabled` | Create ServiceMonitor resource (requires Prometheus Operator) | `false` |
| `serviceMonitor.interval` | Scrape interval | `30s` |
| `serviceMonitor.path` | Metrics endpoint path | `/api/v1/monitoring/metrics` |
| `serviceMonitor.labels` | Additional labels for ServiceMonitor | `{}` |
### Network Policy Parameters
| Parameter | Description | Default |
|-----------|-------------|---------|
| `networkPolicy.enabled` | Enable NetworkPolicy | `false` |
| `networkPolicy.policyTypes` | Policy types | `["Ingress", "Egress"]` |
### Resource Management Parameters
| Parameter | Description | Default |
|-----------|-------------|---------|
| `resources.limits.cpu` | CPU limit | `500m` |
| `resources.limits.memory` | Memory limit | `512Mi` |
| `resources.requests.cpu` | CPU request | `100m` |
| `resources.requests.memory` | Memory request | `128Mi` |
### Health Check Parameters
| Parameter | Description | Default |
|-----------|-------------|---------|
| `livenessProbe.enabled` | Enable liveness probe | `true` |
| `readinessProbe.enabled` | Enable readiness probe | `true` |
### Other Parameters
| Parameter | Description | Default |
|-----------|-------------|---------|
| `podAnnotations` | Pod annotations | `{}` |
| `podSecurityContext` | Pod security context | See `values.yaml` |
| `securityContext` | Container security context | See `values.yaml` |
| `nodeSelector` | Node labels for pod assignment | `{}` |
| `tolerations` | Tolerations for pod assignment | `[]` |
| `affinity` | Affinity for pod assignment | `{}` |
## Configuration Examples
### Example 1: Basic Installation with Custom Garage Endpoints
Create a file named `custom-values.yaml`:
```yaml
config: |
server:
host: "0.0.0.0"
port: 8080
environment: "production"
garage:
endpoint: "http://garage-s3.garage.svc.cluster.local:3900"
region: "us-east-1"
admin_endpoint: "http://garage-admin.garage.svc.cluster.local:3903"
admin_token: "YOUR_ADMIN_TOKEN_HERE"
auth:
mode: "none"
cors:
enabled: true
allowed_origins:
- "*"
logging:
level: "info"
format: "json"
```
Install the chart:
```bash
helm install my-garage-ui ./helm/garage-ui -f custom-values.yaml
```
### Example 2: With Ingress and TLS
```yaml
config: |
server:
host: "0.0.0.0"
port: 8080
environment: "production"
garage:
endpoint: "http://garage:3900"
region: "garage"
admin_endpoint: "http://garage:3903"
admin_token: "YOUR_ADMIN_TOKEN"
auth:
mode: "none"
cors:
enabled: true
logging:
level: "info"
format: "json"
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: garage-ui.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: garage-ui-tls
hosts:
- garage-ui.example.com
```
### Example 3: With Basic Authentication
```yaml
config: |
server:
host: "0.0.0.0"
port: 8080
environment: "production"
garage:
endpoint: "http://garage:3900"
region: "garage"
admin_endpoint: "http://garage:3903"
admin_token: "YOUR_ADMIN_TOKEN"
auth:
mode: "basic"
basic:
username: "admin"
password: "your-secure-password"
cors:
enabled: true
logging:
level: "info"
format: "json"
```
### Example 4: With OIDC Authentication (Keycloak)
```yaml
config: |
server:
host: "0.0.0.0"
port: 8080
environment: "production"
garage:
endpoint: "http://garage:3900"
region: "garage"
admin_endpoint: "http://garage:3903"
admin_token: "YOUR_ADMIN_TOKEN"
auth:
mode: "oidc"
oidc:
enabled: true
provider_name: "Keycloak"
client_id: "garage-ui"
client_secret: "YOUR_OIDC_CLIENT_SECRET"
scopes:
- openid
- email
- profile
issuer_url: "https://keycloak.example.com/realms/master"
auth_url: "https://keycloak.example.com/realms/master/protocol/openid-connect/auth"
token_url: "https://keycloak.example.com/realms/master/protocol/openid-connect/token"
userinfo_url: "https://keycloak.example.com/realms/master/protocol/openid-connect/userinfo"
cookie_secure: true
cors:
enabled: true
logging:
level: "info"
format: "json"
```
### Example 5: With Prometheus Monitoring
```yaml
config: |
server:
host: "0.0.0.0"
port: 8080
environment: "production"
garage:
endpoint: "http://garage:3900"
region: "garage"
admin_endpoint: "http://garage:3903"
admin_token: "YOUR_ADMIN_TOKEN"
auth:
mode: "none"
cors:
enabled: true
logging:
level: "info"
format: "json"
serviceMonitor:
enabled: true
interval: 30s
labels:
prometheus: kube-prometheus
```
## Accessing the Application
### Via Port Forward (Development)
```bash
kubectl port-forward svc/my-garage-ui 8080:80
```
Then visit http://localhost:8080 in your browser.
### Via Ingress (Production)
If you've enabled Ingress, access the application at the configured hostname (e.g., https://garage-ui.example.com).
## Upgrading
To upgrade the `my-garage-ui` deployment:
```bash
helm upgrade my-garage-ui ./helm/garage-ui -f custom-values.yaml
```
## Configuration Details
### Garage Endpoints
The application requires two Garage endpoints:
- **S3 API Endpoint** (`garage.endpoint`): The Garage S3 API endpoint (default port 3900)
- **Admin API Endpoint** (`garage.admin_endpoint`): The Garage Admin API endpoint (default port 3903)
- **Admin Token** (`garage.admin_token`): Bearer token for Admin API authentication (required)
### Authentication Modes
The application supports three authentication modes:
1. **None** (`auth.mode: "none"`): No authentication required
2. **Basic** (`auth.mode: "basic"`): HTTP Basic authentication with username/password
3. **OIDC** (`auth.mode: "oidc"`): OpenID Connect for enterprise SSO
### Health Checks
The application exposes a health check endpoint at `/health` which is used for:
- Kubernetes liveness probes
- Kubernetes readiness probes
- Manual health verification
### Metrics
When ServiceMonitor is enabled, Prometheus will scrape metrics from `/api/v1/monitoring/metrics`. This endpoint proxies metrics from the Garage Admin API.
## Troubleshooting
### Pods not starting
Check if the config is valid:
```bash
kubectl logs -l app.kubernetes.io/name=garage-ui
```
Common issues:
- Missing or invalid `garage.admin_token`
- Unreachable Garage endpoints
- Invalid OIDC configuration when using `auth.mode: "oidc"`
### Can't access the UI
If using Ingress:
```bash
kubectl get ingress
kubectl describe ingress <ingress-name>
```
If using port-forward:
```bash
kubectl get pods
kubectl port-forward <pod-name> 8080:8080
```
### Configuration not updating
The deployment includes a checksum annotation for the ConfigMap. Changes to the config will automatically trigger a pod restart. If not:
```bash
kubectl rollout restart deployment/my-garage-ui
```
## License
This Helm chart is open source and available under the same license as Garage UI.
## Support
For issues and questions:
- GitHub Issues: https://github.com/Noooste/garage-ui/issues
- Garage Documentation: https://garagehq.deuxfleurs.fr/
## Contributing
Contributions are welcome! Please submit pull requests to the Garage UI repository.
+27
View File
@@ -0,0 +1,27 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "garage-ui.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "garage-ui.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "garage-ui.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "garage-ui.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
{{- end }}
2. To view logs:
kubectl logs -f deployment/{{ include "garage-ui.fullname" . }} -n {{ .Release.Namespace }}
For more information, see the README at https://github.com/Noooste/garage-ui/blob/main/helm/garage-ui/README.md
+51
View File
@@ -0,0 +1,51 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "garage-ui.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "garage-ui.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "garage-ui.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "garage-ui.labels" -}}
helm.sh/chart: {{ include "garage-ui.chart" . }}
{{ include "garage-ui.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "garage-ui.selectorLabels" -}}
app.kubernetes.io/name: {{ include "garage-ui.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
+9
View File
@@ -0,0 +1,9 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "garage-ui.fullname" . }}-config
labels:
{{- include "garage-ui.labels" . | nindent 4 }}
data:
config.yaml: |
{{- .Values.config | toYaml | nindent 4 }}
+80
View File
@@ -0,0 +1,80 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "garage-ui.fullname" . }}
labels:
{{- include "garage-ui.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "garage-ui.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "garage-ui.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 8080
protocol: TCP
{{- if .Values.livenessProbe.enabled }}
livenessProbe:
httpGet:
path: {{ .Values.livenessProbe.httpGet.path }}
port: {{ .Values.livenessProbe.httpGet.port }}
initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.livenessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.livenessProbe.failureThreshold }}
{{- end }}
{{- if .Values.readinessProbe.enabled }}
readinessProbe:
httpGet:
path: {{ .Values.readinessProbe.httpGet.path }}
port: {{ .Values.readinessProbe.httpGet.port }}
initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.readinessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.readinessProbe.failureThreshold }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: config
mountPath: /app/config.yaml
subPath: config.yaml
readOnly: true
volumes:
- name: config
configMap:
name: {{ include "garage-ui.fullname" . }}-config
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
+41
View File
@@ -0,0 +1,41 @@
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "garage-ui.fullname" . }}
labels:
{{- include "garage-ui.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "garage-ui.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}
@@ -0,0 +1,26 @@
{{- if .Values.networkPolicy.enabled -}}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "garage-ui.fullname" . }}
labels:
{{- include "garage-ui.labels" . | nindent 4 }}
spec:
podSelector:
matchLabels:
{{- include "garage-ui.selectorLabels" . | nindent 6 }}
policyTypes:
{{- toYaml .Values.networkPolicy.policyTypes | nindent 4 }}
ingress:
- from: []
ports:
- protocol: TCP
port: 8080
egress:
- to: []
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
{{- end }}
+15
View File
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "garage-ui.fullname" . }}
labels:
{{- include "garage-ui.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "garage-ui.selectorLabels" . | nindent 4 }}
@@ -0,0 +1,19 @@
{{- if .Values.serviceMonitor.enabled -}}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "garage-ui.fullname" . }}
labels:
{{- include "garage-ui.labels" . | nindent 4 }}
{{- with .Values.serviceMonitor.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
selector:
matchLabels:
{{- include "garage-ui.selectorLabels" . | nindent 6 }}
endpoints:
- port: http
path: {{ .Values.serviceMonitor.path }}
interval: {{ .Values.serviceMonitor.interval }}
{{- end }}
+553
View File
@@ -0,0 +1,553 @@
# Default values for garage-ui Helm chart
# This file contains configuration values for deploying Garage UI
# Customize the values below according to your deployment environment
# Number of replica pods to run
# Increase for high availability (recommended: 2-3 for production)
replicaCount: 1
# Docker image configuration
image:
# Container registry and image name
# Default uses the official Garage UI image from Docker Hub
repository: noooste/garage-ui
# Image pull policy
# Options: Always, IfNotPresent, Never
# IfNotPresent: Only pull if image is not already present locally
pullPolicy: IfNotPresent
# Image tag to use (defaults to chart appVersion if empty)
# Example: "1.0.0" or "latest"
tag: ""
# Credentials for accessing private container registries
# Example:
# imagePullSecrets:
# - name: regcred
imagePullSecrets: []
# Override the default chart name in resource names
# Leave empty to use the chart name
nameOverride: ""
# Override the full resource name (includes release name)
# Leave empty to use the default naming convention
fullnameOverride: ""
# ============================================================================
# APPLICATION CONFIGURATION
# ============================================================================
# This section contains the main application configuration
# Customize according to your Garage deployment and security requirements
#
# TIP: You can now easily override specific values using --set:
# --set config.server.port=9090
# --set config.garage.admin_token=your-token
# --set config.auth.mode=basic
config:
# ========================================
# Server Configuration
# ========================================
server:
# Network interface to bind to
# "0.0.0.0" listens on all interfaces (recommended for containers)
host: "0.0.0.0"
# Port the application listens on
# Default: 8080
port: 8080
# Deployment environment
# Options: "production", "development", "staging"
environment: "production"
# ========================================
# Garage S3 Storage Configuration
# ========================================
garage:
# Garage S3 API endpoint
# Format: http(s)://hostname:port
# Default port: 3900
# Example: "http://garage.example.com:3900" or "http://garage:3900" for in-cluster
endpoint: "http://garage:3900"
# S3 region name
# For Garage, this can be any arbitrary value (Garage ignores regions)
# Default: "garage"
region: "garage"
# Garage Admin API endpoint
# This is used for administrative operations like bucket and key management
# Default port: 3903
# Example: "http://garage.example.com:3903" or "http://garage:3903" for in-cluster
admin_endpoint: "http://garage:3903"
# Admin API bearer token
# REQUIRED: Obtain this from your Garage server configuration
# This token grants administrative access - keep it secure!
# To generate: See Garage documentation for admin token setup
admin_token: ""
# ========================================
# Authentication Configuration
# ========================================
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"
# Provides simple username/password protection
basic:
# Username for basic auth login
username: "admin"
# Password for basic auth login
# IMPORTANT: Change this default password immediately!
password: "changeme"
# OpenID Connect (OIDC) Configuration
# Only used when mode = "oidc"
# Integrates with identity providers like Keycloak, Auth0, Okta, etc.
oidc:
# Enable/disable OIDC (must be true when mode = "oidc")
enabled: false
# Display name of your OIDC provider
# Examples: "Keycloak", "Auth0", "Okta", "Azure AD"
provider_name: "Keycloak"
# OAuth2 client ID registered with your OIDC provider
# Obtain this from your OIDC provider's application settings
client_id: "garage-ui"
# OAuth2 client secret registered with your OIDC provider
# IMPORTANT: Keep this secret secure! Consider using Kubernetes secrets
client_secret: "your-client-secret"
# OAuth2/OIDC scopes to request during authentication
# Standard scopes: openid (required), email, profile
# Add custom scopes as needed by your provider
scopes:
- openid
- email
- profile
# OIDC Provider Endpoints
# Replace "keycloak.example.com" and realm with your actual values
# For Keycloak: https://your-keycloak/realms/your-realm
# For Auth0: https://your-tenant.auth0.com
# For Okta: https://your-domain.okta.com
# OIDC issuer URL (base URL for OIDC discovery)
issuer_url: "https://keycloak.example.com/realms/master"
# Authorization endpoint URL
auth_url: "https://keycloak.example.com/realms/master/protocol/openid-connect/auth"
# Token endpoint URL
token_url: "https://keycloak.example.com/realms/master/protocol/openid-connect/token"
# User info endpoint URL
userinfo_url: "https://keycloak.example.com/realms/master/protocol/openid-connect/userinfo"
# Token Validation Settings
# Set to true only if you have issuer mismatch issues (not recommended)
skip_issuer_check: false
# Set to true to skip token expiry validation (not recommended for production)
skip_expiry_check: false
# User Attribute Mappings
# Map OIDC claims to application user attributes
# Adjust these based on your OIDC provider's claim structure
# Claim containing user's email address
email_attribute: "email"
# Claim containing user's username/login ID
username_attribute: "preferred_username"
# Claim containing user's display name
name_attribute: "name"
# Role-Based Access Control (Optional)
# Path to roles in the OIDC token claims
# Example for Keycloak: "resource_access.garage-ui.roles"
# Example for Auth0: "https://your-app/roles"
role_attribute_path: "resource_access.garage-ui.roles"
# Role name that grants admin privileges
# Users with this role will have full administrative access
admin_role: "admin"
# TLS/SSL Configuration
# Skip TLS certificate verification (only for testing - never in production!)
tls_skip_verify: false
# Session Management
# How long user sessions remain valid without activity
# Value in seconds (86400 = 24 hours)
session_max_age: 86400
# Name of the session cookie
cookie_name: "garage_session"
# Only send cookie over HTTPS connections
# Set to false only for local development without HTTPS
cookie_secure: true
# Prevent JavaScript access to the cookie (security feature)
# Should remain true for security
cookie_http_only: true
# SameSite cookie attribute for CSRF protection
# Options: "lax" (recommended), "strict", "none"
# Use "lax" for most cases, "strict" for maximum security
cookie_same_site: "lax"
# ========================================
# CORS (Cross-Origin Resource Sharing)
# ========================================
# Configure which origins can access the API from browsers
cors:
# Enable or disable CORS
# Disable if the frontend and backend are served from the same origin
enabled: true
# List of allowed origins
# "*" allows all origins (convenient but less secure)
# For production, specify exact origins:
# Example:
# - "https://garage-ui.example.com"
# - "https://app.example.com"
allowed_origins:
- "*"
# HTTP methods that are allowed in CORS requests
# Include all methods your API uses
allowed_methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
# HTTP headers that are allowed in CORS requests
# Add any custom headers your application requires
allowed_headers:
- Origin
- Content-Type
- Accept
- Authorization
# Allow credentials (cookies, authorization headers) in CORS requests
# Set to true if your frontend needs to send authentication cookies
# NOTE: When true, allowed_origins cannot be "*"
allow_credentials: false
# How long browsers can cache CORS preflight responses (in seconds)
# 3600 = 1 hour
max_age: 3600
# ========================================
# Logging Configuration
# ========================================
logging:
# Log verbosity level
# Options:
# "debug" - Verbose logging, useful for troubleshooting
# "info" - Standard logging (recommended for production)
# "warn" - Only warnings and errors
# "error" - Only errors
level: "info"
# Log output format
# Options:
# "json" - Structured JSON format (recommended for production/log aggregation)
# "text" - Human-readable text format (useful for development)
format: "json"
# ============================================================================
# KUBERNETES POD CONFIGURATION
# ============================================================================
# Annotations to add to the pod
# Use for integrations with service meshes, monitoring, etc.
# Example:
# podAnnotations:
# prometheus.io/scrape: "true"
# prometheus.io/port: "8080"
podAnnotations: {}
# Pod-level security context
# Defines security settings for all containers in the pod
podSecurityContext:
# Run containers as non-root user (security best practice)
runAsNonRoot: true
# User ID to run containers as
# Default: 1000 (non-privileged user)
runAsUser: 1000
# Group ID for filesystem access
# Files created by the pod will have this group ownership
fsGroup: 1000
# Container-level security context
# Security settings specific to the application container
securityContext:
# Prevent privilege escalation (security best practice)
# Ensures the container cannot gain more privileges than its parent
allowPrivilegeEscalation: false
# Drop all Linux capabilities and only add what's needed
# This follows the principle of least privilege
capabilities:
drop:
- ALL
# Allow write access to the root filesystem
# Set to true for read-only root filesystem (more secure but may require adjustments)
readOnlyRootFilesystem: false
# ============================================================================
# KUBERNETES SERVICE
# ============================================================================
service:
# Service type determines how the service is exposed
# Options:
# ClusterIP - Internal only (default, recommended when using Ingress)
# NodePort - Expose on each node's IP at a static port
# LoadBalancer - Expose using a cloud provider's load balancer
type: ClusterIP
# Port the service listens on
# This is the port other services/ingress will connect to
# Default: 80
port: 80
# ============================================================================
# INGRESS CONFIGURATION
# ============================================================================
# Ingress exposes HTTP/HTTPS routes from outside the cluster to the service
ingress:
# Enable or disable ingress
# Set to true to make the application accessible from outside the cluster
enabled: false
# Ingress class name
# Specifies which ingress controller to use
# Common values: "nginx", "traefik", "alb" (AWS)
# Ensure the specified controller is installed in your cluster
className: "nginx"
# Additional annotations for the ingress
# Use for configuring ingress controller behavior, SSL, authentication, etc.
# Examples:
# cert-manager.io/cluster-issuer: "letsencrypt-prod" # For automatic SSL certificates
# nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
# nginx.ingress.kubernetes.io/proxy-body-size: "100m"
annotations: {}
# Hostname and path configuration
hosts:
# Replace "garage-ui.local" with your actual domain
- host: garage-ui.local
paths:
# Path where the application will be accessible
- path: /
# pathType options: Prefix, Exact, ImplementationSpecific
pathType: Prefix
# TLS/SSL configuration
# Uncomment and configure to enable HTTPS
# Requires a TLS certificate stored in a Kubernetes secret
tls: []
# - secretName: garage-ui-tls
# hosts:
# - garage-ui.local
#
# To use cert-manager for automatic certificates:
# 1. Install cert-manager in your cluster
# 2. Create a ClusterIssuer (e.g., letsencrypt-prod)
# 3. Add annotation: cert-manager.io/cluster-issuer: "letsencrypt-prod"
# 4. Uncomment the tls section above
# ============================================================================
# RESOURCE LIMITS AND REQUESTS
# ============================================================================
# Configure CPU and memory allocation for the pods
# Requests: Guaranteed resources (used for scheduling)
# Limits: Maximum resources the container can use
resources:
limits:
# Maximum CPU cores the container can use
# 500m = 0.5 CPU cores
# Increase for high-traffic deployments
cpu: 500m
# Maximum memory the container can use
# Container will be killed if it exceeds this limit
memory: 512Mi
requests:
# Guaranteed CPU allocated to the container
# 100m = 0.1 CPU cores
# Cluster scheduler ensures this amount is available
cpu: 100m
# Guaranteed memory allocated to the container
# Cluster scheduler ensures this amount is available
memory: 128Mi
# ============================================================================
# HEALTH CHECKS
# ============================================================================
# Liveness Probe
# Kubernetes restarts the container if this probe fails
# Detects if the application is running but in a broken state
livenessProbe:
# Enable or disable the liveness probe
enabled: true
# HTTP endpoint to check
httpGet:
# Health check endpoint path
path: /health
# Port name (defined in the container spec)
port: http
# Wait time before starting liveness checks after container starts
# Give the application time to initialize
initialDelaySeconds: 30
# How often to perform the probe (in seconds)
periodSeconds: 10
# Maximum time to wait for the probe to complete
timeoutSeconds: 3
# Number of consecutive failures before restarting the container
failureThreshold: 3
# Readiness Probe
# Kubernetes stops sending traffic if this probe fails
# Determines when the container is ready to accept traffic
readinessProbe:
# Enable or disable the readiness probe
enabled: true
# HTTP endpoint to check
httpGet:
# Readiness check endpoint path
path: /health
# Port name (defined in the container spec)
port: http
# Wait time before starting readiness checks after container starts
initialDelaySeconds: 10
# How often to perform the probe (in seconds)
periodSeconds: 5
# Maximum time to wait for the probe to complete
timeoutSeconds: 3
# Number of consecutive failures before marking as not ready
failureThreshold: 3
# ============================================================================
# MONITORING AND OBSERVABILITY
# ============================================================================
# ServiceMonitor for Prometheus Operator
# Automatically configure Prometheus to scrape metrics from the application
# Requires Prometheus Operator to be installed in the cluster
serviceMonitor:
# Enable or disable ServiceMonitor creation
# Set to true if using Prometheus Operator for monitoring
enabled: false
# How often Prometheus should scrape metrics
# Format: duration string (e.g., "30s", "1m", "5m")
interval: 30s
# Metrics endpoint path
# The application exposes metrics at this path
path: /api/v1/monitoring/metrics
# Additional labels for the ServiceMonitor
# Use to match Prometheus scrape configurations
# Example:
# labels:
# prometheus: kube-prometheus
labels: {}
# ============================================================================
# NETWORK POLICY
# ============================================================================
# Controls network traffic to/from the pods
# Requires a network plugin that supports NetworkPolicy (e.g., Calico, Cilium)
networkPolicy:
# Enable or disable NetworkPolicy creation
# Provides network-level security by restricting pod communication
enabled: false
# Types of policies to enforce
# Ingress: Controls incoming traffic to the pod
# Egress: Controls outgoing traffic from the pod
policyTypes:
- Ingress
- Egress
# Note: When enabled, by default only allows necessary traffic
# Customize the NetworkPolicy template if you need specific rules
# ============================================================================
# POD SCHEDULING
# ============================================================================
# Node Selector
# Schedule pods only on nodes with specific labels
# Useful for deploying to specific node pools or hardware types
# Example:
# nodeSelector:
# disktype: ssd
# environment: production
nodeSelector: {}
# Tolerations
# Allow pods to be scheduled on nodes with matching taints
# Useful for dedicated node pools or special hardware
# Example:
# tolerations:
# - key: "dedicated"
# operator: "Equal"
# value: "garage-ui"
# effect: "NoSchedule"
tolerations: []
# Affinity Rules
# Advanced pod scheduling constraints
# Controls which nodes pods can be scheduled on and pod co-location
# Example for pod anti-affinity (spread pods across nodes):
# affinity:
# podAntiAffinity:
# preferredDuringSchedulingIgnoredDuringExecution:
# - weight: 100
# podAffinityTerm:
# labelSelector:
# matchExpressions:
# - key: app.kubernetes.io/name
# operator: In
# values:
# - garage-ui
# topologyKey: kubernetes.io/hostname
affinity: {}