# Apache Superset Helm values # https://github.com/apache/superset/tree/master/helm/superset # Service configuration service: type: ClusterIP port: 8088 # Ingress configuration ingress: enabled: true ingressClassName: traefik annotations: kubernetes.io/ingress.class: traefik traefik.ingress.kubernetes.io/router.entrypoints: websecure hosts: - {{ env.Getenv "SUPERSET_HOST" }} tls: - secretName: superset-tls hosts: - {{ env.Getenv "SUPERSET_HOST" }} # Init job settings (disable to use external database initialization) init: enabled: true createAdmin: false loadExamples: false # Security context for Pod Security Standards (baseline) podSecurityContext: fsGroup: 1000 fsGroupChangePolicy: OnRootMismatch seccompProfile: type: RuntimeDefault containerSecurityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: false runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 seccompProfile: type: RuntimeDefault capabilities: drop: - ALL initContainers: - name: copy-venv image: apachesuperset.docker.scarf.sh/apache/superset:5.0.0 command: - sh - -c - | if [ ! -d /venv-target/lib ]; then echo "Copying .venv to emptyDir..." cp -a /app/.venv/. /venv-target/ chown -R 1000:1000 /venv-target else echo ".venv already initialized" fi volumeMounts: - name: superset-venv mountPath: /venv-target securityContext: runAsUser: 0 # Superset node configuration supersetNode: replicaCount: 1 # Security context for Pod Security Standards (baseline) podSecurityContext: fsGroup: 1000 fsGroupChangePolicy: OnRootMismatch seccompProfile: type: RuntimeDefault containerSecurityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: false runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 seccompProfile: type: RuntimeDefault capabilities: drop: - ALL initContainers: - name: copy-venv image: apachesuperset.docker.scarf.sh/apache/superset:5.0.0 command: - sh - -c - | if [ ! -d /venv-target/lib ]; then echo "Copying .venv to emptyDir..." cp -a /app/.venv/. /venv-target/ chown -R 1000:1000 /venv-target else echo ".venv already initialized" fi volumeMounts: - name: superset-venv mountPath: /venv-target securityContext: runAsUser: 0 connections: # Redis configuration redis_host: superset-redis-headless redis_port: "6379" redis_cache_db: "1" redis_celery_db: "0" # PostgreSQL configuration for initContainer (wait-for-postgres) # The actual database connection uses SQLALCHEMY_DATABASE_URI from extraEnvRaw db_host: postgres-cluster-rw.postgres db_port: "5432" db_user: superset db_pass: {{ env.Getenv "SUPERSET_DB_PASSWORD" }} db_name: superset # Superset worker (Celery) configuration supersetWorker: replicaCount: 1 # Security context for Pod Security Standards (baseline) podSecurityContext: fsGroup: 1000 fsGroupChangePolicy: OnRootMismatch seccompProfile: type: RuntimeDefault containerSecurityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: false runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 seccompProfile: type: RuntimeDefault capabilities: drop: - ALL initContainers: - name: copy-venv image: apachesuperset.docker.scarf.sh/apache/superset:5.0.0 command: - sh - -c - | if [ ! -d /venv-target/lib ]; then echo "Copying .venv to emptyDir..." cp -a /app/.venv/. /venv-target/ chown -R 1000:1000 /venv-target else echo ".venv already initialized" fi volumeMounts: - name: superset-venv mountPath: /venv-target securityContext: runAsUser: 0 # Database configuration (use existing PostgreSQL) postgresql: enabled: false # Redis configuration (embedded) redis: enabled: true image: registry: docker.io repository: bitnami/redis # Since August 2025, Bitnami changed its strategy: # - Community users can only use 'latest' tag (no version pinning) # - Versioned tags moved to 'bitnamilegacy' repository (deprecated, no updates) # - For production with version pinning, consider using official redis image separately tag: latest master: persistence: enabled: false # Security context for Pod Security Standards (restricted) podSecurityContext: runAsNonRoot: true runAsUser: 1001 runAsGroup: 1001 fsGroup: 1001 fsGroupChangePolicy: OnRootMismatch seccompProfile: type: RuntimeDefault containerSecurityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: false runAsNonRoot: true runAsUser: 1001 runAsGroup: 1001 seccompProfile: type: RuntimeDefault capabilities: drop: - ALL # Extra environment variables extraEnv: KEYCLOAK_HOST: {{ env.Getenv "KEYCLOAK_HOST" }} KEYCLOAK_REALM: {{ env.Getenv "KEYCLOAK_REALM" }} # Extra environment variables from existing secrets extraEnvRaw: - name: SUPERSET_SECRET_KEY valueFrom: secretKeyRef: name: superset-secret key: SECRET_KEY - name: SQLALCHEMY_DATABASE_URI valueFrom: secretKeyRef: name: superset-secret key: SQLALCHEMY_DATABASE_URI - name: OAUTH_CLIENT_SECRET valueFrom: secretKeyRef: name: superset-secret key: OAUTH_CLIENT_SECRET # Configuration overrides for superset_config.py configOverrides: keycloak_oauth: | import os from flask_appbuilder.security.manager import AUTH_OAUTH from superset.security import SupersetSecurityManager class CustomSsoSecurityManager(SupersetSecurityManager): def oauth_user_info(self, provider, response=None): """Get user information from OAuth provider.""" if provider == "keycloak": me = self.appbuilder.sm.oauth_remotes[provider].get( "protocol/openid-connect/userinfo" ) data = me.json() return { "username": data.get("preferred_username"), "name": data.get("name"), "email": data.get("email"), "first_name": data.get("given_name", ""), "last_name": data.get("family_name", ""), "role_keys": data.get("groups", []), } return {} # Authentication type AUTH_TYPE = AUTH_OAUTH # Auto-registration for new users AUTH_USER_REGISTRATION = True AUTH_USER_REGISTRATION_ROLE = "Gamma" # Custom security manager CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager # OAuth configuration OAUTH_PROVIDERS = [ { "name": "keycloak", "icon": "fa-key", "token_key": "access_token", "remote_app": { "client_id": "superset", "client_secret": os.environ.get("OAUTH_CLIENT_SECRET"), "server_metadata_url": f"https://{os.environ.get('KEYCLOAK_HOST')}/realms/{os.environ.get('KEYCLOAK_REALM')}/.well-known/openid-configuration", "api_base_url": f"https://{os.environ.get('KEYCLOAK_HOST')}/realms/{os.environ.get('KEYCLOAK_REALM')}/", "client_kwargs": { "scope": "openid email profile" }, } } ] # Role mapping AUTH_ROLES_MAPPING = { "superset-admin": ["Admin"], "Alpha": ["Alpha"], "Gamma": ["Gamma"], } # Sync roles at each login AUTH_ROLES_SYNC_AT_LOGIN = True # Enable Trino database support PREVENT_UNSAFE_DB_CONNECTIONS = False # Proxy configuration (for HTTPS behind Traefik) ENABLE_PROXY_FIX = True PREFERRED_URL_SCHEME = "https" # Disable SQL Lab backend persistence to avoid tab state migration errors SQLLAB_BACKEND_PERSISTENCE = False # Bootstrap script for initial setup # Note: Superset 5.0+ uses 'uv' instead of 'pip' for package management bootstrapScript: | #!/bin/bash uv pip install psycopg2-binary sqlalchemy-trino authlib if [ ! -f ~/bootstrap ]; then echo "Bootstrap complete" > ~/bootstrap; fi # Extra volumes and volume mounts for cache directories and venv extraVolumes: - name: superset-cache emptyDir: {} - name: superset-venv emptyDir: {} extraVolumeMounts: - name: superset-cache mountPath: /app/superset_home/.cache - name: superset-venv mountPath: /app/.venv